mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-19 23:55:29 +00:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bfbf6d3f94 | |||
| 0c4180c74b | |||
| 1c6ae435bf | |||
| 66b6d3c497 | |||
| 8c252c9822 | |||
| 450dc2115c | |||
| 87a6890900 | |||
| 83ab12c387 | |||
| 3f444dad8d | |||
| f23315d08b | |||
| 7b116be344 | |||
| 934e4c9bd4 | |||
| 1966fb25c5 | |||
| a333d8514a | |||
| b146c7131e | |||
| 53093ebceb | |||
| 401b2decce | |||
| 83a164e5ef | |||
| d91bc45cdc | |||
| 8967912f46 | |||
| 7ab2cafbee | |||
| 7e0ed2235e | |||
| 53abb7b4bd | |||
| 11f86b8813 | |||
| 9997a9f47e | |||
| 4aedb33d37 | |||
| 4ddc36c625 | |||
| 311f88a716 | |||
| 179cb49dbc | |||
| 512e390738 | |||
| 33b677aeb4 | |||
| 800598ced4 | |||
| ec20f27a82 | |||
| cd59c1c075 | |||
| 52b0f2c3c9 | |||
| 598f44f4c2 | |||
| 22d0dd1301 | |||
| c6b6b0a370 | |||
| ee6c8a5995 | |||
| d5a1a48145 | |||
| 963edbf191 | |||
| 43c3c8f568 |
+56
-31
@@ -67,6 +67,7 @@ Here's how to make a one-off code change.
|
||||
$ git checkout -b your-branch-name
|
||||
|
||||
3. **Make a commit to your feature branch**. Each commit should be self-contained and have a descriptive commit message that helps other developers understand why the changes were made.
|
||||
We also have a check-list for PRs `below`_.
|
||||
|
||||
- You can refer to relevant issues in the commit message by writing, e.g., "#105".
|
||||
|
||||
@@ -80,39 +81,17 @@ Here's how to make a one-off code change.
|
||||
|
||||
- The following exceptions to the above (Google's) style guides applies:
|
||||
|
||||
- Documenting types of global variables and complex types of class members can be done using the Sphinx docstring convention.
|
||||
- Documenting types of global variables and complex types of class members can be done using the Sphinx docstring convention.
|
||||
|
||||
- In addition, PTB uses some formatting/styling and linting tools in the pre-commit setup. Some of those tools also have command line tools that can help to run these tools outside of the pre-commit step. If you'd like to leverage that, please have a look at the `pre-commit config file`_ for an overview of which tools (and which versions of them) are used. For example, we use `Black`_ for code formatting. Plugins for Black exist for some `popular editors`_. You can use those instead of manually formatting everything.
|
||||
|
||||
- Please ensure that the code you write is well-tested.
|
||||
- Please ensure that the code you write is well-tested and that all automated tests still pass. We
|
||||
have dedicated an `testing page`_ to help you with that.
|
||||
|
||||
- In addition to that, we provide the `dev` marker for pytest. If you write one or multiple tests and want to run only those, you can decorate them via `@pytest.mark.dev` and then run it with minimal overhead with `pytest ./path/to/test_file.py -m dev`.
|
||||
|
||||
- Don’t break backward compatibility.
|
||||
- Don't break backward compatibility.
|
||||
|
||||
- Add yourself to the AUTHORS.rst_ file in an alphabetical fashion.
|
||||
|
||||
- Before making a commit ensure that all automated tests still pass:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ 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
|
||||
|
||||
$ export TEST_OFFICIAL=true
|
||||
|
||||
prior to running the tests.
|
||||
|
||||
- If you want run style & type checks before committing run
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -143,11 +122,11 @@ Here's how to make a one-off code change.
|
||||
|
||||
- When your reviewer has reviewed the code, you'll get a notification. You'll need to respond in two ways:
|
||||
|
||||
- Make a new commit addressing the comments you agree with, and push it to the same branch. Ideally, the commit message would explain what the commit does (e.g. "Fix lint error"), but if there are lots of disparate review comments, it's fine to refer to the original commit message and add something like "(address review comments)".
|
||||
- Make a new commit addressing the comments you agree with, and push it to the same branch. Ideally, the commit message would explain what the commit does (e.g. "Fix lint error"), but if there are lots of disparate review comments, it's fine to refer to the original commit message and add something like "(address review comments)".
|
||||
|
||||
- In order to keep the commit history intact, please avoid squashing or amending history and then force-pushing to the PR. Reviewers often want to look at individual commits.
|
||||
- In order to keep the commit history intact, please avoid squashing or amending history and then force-pushing to the PR. Reviewers often want to look at individual commits.
|
||||
|
||||
- In addition, please reply to each comment. Each reply should be either "Done" or a response explaining why the corresponding suggestion wasn't implemented. All comments must be resolved before LGTM can be given.
|
||||
- In addition, please reply to each comment. Each reply should be either "Done" or a response explaining why the corresponding suggestion wasn't implemented. All comments must be resolved before LGTM can be given.
|
||||
|
||||
- Resolve any merge conflicts that arise. To resolve conflicts between 'your-branch-name' (in your fork) and 'master' (in the ``python-telegram-bot`` repository), run:
|
||||
|
||||
@@ -172,6 +151,51 @@ Here's how to make a one-off code change.
|
||||
|
||||
7. **Celebrate.** Congratulations, you have contributed to ``python-telegram-bot``!
|
||||
|
||||
Check-list for PRs
|
||||
------------------
|
||||
|
||||
This checklist is a non-exhaustive reminder of things that should be done before a PR is merged, both for you as contributor and for the maintainers.
|
||||
Feel free to copy (parts of) the checklist to the PR description to remind you or the maintainers of open points or if you have questions on anything.
|
||||
|
||||
- Added ``.. versionadded:: NEXT.VERSION``, ``.. versionchanged:: NEXT.VERSION`` or ``.. deprecated:: NEXT.VERSION`` to the docstrings for user facing changes (for methods/class descriptions, arguments and attributes)
|
||||
- Created new or adapted existing unit tests
|
||||
- Documented code changes according to the `CSI standard <https://standards.mousepawmedia.com/en/stable/csi.html>`__
|
||||
- Added myself alphabetically to ``AUTHORS.rst`` (optional)
|
||||
- Added new classes & modules to the docs and all suitable ``__all__`` s
|
||||
- Checked the `Stability Policy <https://docs.python-telegram-bot.org/stability_policy.html>`_ in case of deprecations or changes to documented behavior
|
||||
|
||||
**If the PR contains API changes (otherwise, you can ignore this passage)**
|
||||
|
||||
- Checked the Bot API specific sections of the `Stability Policy <https://docs.python-telegram-bot.org/stability_policy.html>`_
|
||||
|
||||
- New classes:
|
||||
|
||||
- Added ``self._id_attrs`` and corresponding documentation
|
||||
- ``__init__`` accepts ``api_kwargs`` as kw-only
|
||||
|
||||
- Added new shortcuts:
|
||||
|
||||
- In :class:`~telegram.Chat` & :class:`~telegram.User` for all methods that accept ``chat/user_id``
|
||||
- In :class:`~telegram.Message` for all methods that accept ``chat_id`` and ``message_id``
|
||||
- For new :class:`~telegram.Message` shortcuts: Added ``quote`` argument if methods accepts ``reply_to_message_id``
|
||||
- In :class:`~telegram.CallbackQuery` for all methods that accept either ``chat_id`` and ``message_id`` or ``inline_message_id``
|
||||
|
||||
- If relevant:
|
||||
|
||||
- Added new constants at :mod:`telegram.constants` and shortcuts to them as class variables
|
||||
- Link new and existing constants in docstrings instead of hard-coded numbers and strings
|
||||
- Add new message types to :attr:`telegram.Message.effective_attachment`
|
||||
- Added new handlers for new update types
|
||||
|
||||
- Add the handlers to the warning loop in the :class:`~telegram.ext.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_INFO``
|
||||
- Added logic for arbitrary callback data in :class:`telegram.ext.ExtBot` for new methods that either accept a ``reply_markup`` in some form or have a return type that is/contains :class:`~telegram.Message`
|
||||
|
||||
Documenting
|
||||
===========
|
||||
|
||||
@@ -205,7 +229,7 @@ or, if you don't have ``make`` available (e.g. on Windows):
|
||||
|
||||
Once the process terminates, you can view the built documentation by opening ``docs/build/html/index.html`` with a browser.
|
||||
|
||||
- Add ``.. versionadded:: version``, ``.. versionchanged:: version`` or ``.. deprecated:: version`` to the associated documentation of your changes, depending on what kind of change you made. This only applies if the change you made is visible to an end user. The directives should be added to class/method descriptions if their general behaviour changed and to the description of all arguments & attributes that changed.
|
||||
- Add ``.. versionadded:: NEXT.VERSION``, ``.. versionchanged:: NEXT.VERSION`` or ``.. deprecated:: NEXT.VERSION`` to the associated documentation of your changes, depending on what kind of change you made. This only applies if the change you made is visible to an end user. The directives should be added to class/method descriptions if their general behaviour changed and to the description of all arguments & attributes that changed.
|
||||
|
||||
Dev facing documentation
|
||||
------------------------
|
||||
@@ -287,4 +311,5 @@ 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
|
||||
.. _`testing page`: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/tests/README.rst
|
||||
.. _`below`: #check-list-for-prs
|
||||
|
||||
@@ -1,38 +1,6 @@
|
||||
<!--
|
||||
Hey! You're PRing? Cool! Please have a look at the below checklist. It's here to help both you and the maintainers to remember some aspects. Make sure to check out our contribution guide (https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.github/CONTRIBUTING.rst).
|
||||
Hey! You're PRing? Cool!
|
||||
Please be sure to check out our contribution guide (https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.github/CONTRIBUTING.rst).
|
||||
Especially, please have a look at the check list for PRs (https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.github/CONTRIBUTING.rst#checklist-for-prs). Feel free to copy (parts of) the checklist to the PR description to remind you or the maintainers of open points or if you have questions on anything.
|
||||
-->
|
||||
|
||||
### Checklist for PRs
|
||||
|
||||
- [ ] Added `.. versionadded:: version`, `.. versionchanged:: version` or `.. deprecated:: version` to the docstrings for user facing changes (for methods/class descriptions, arguments and attributes)
|
||||
- [ ] Created new or adapted existing unit tests
|
||||
- [ ] Documented code changes according to the [CSI standard](https://standards.mousepawmedia.com/en/stable/csi.html)
|
||||
- [ ] Added myself alphabetically to `AUTHORS.rst` (optional)
|
||||
- [ ] Added new classes & modules to the docs and all suitable `__all__` s
|
||||
|
||||
|
||||
### If the PR contains API changes (otherwise, you can delete this passage)
|
||||
|
||||
* New classes:
|
||||
- [ ] Added `self._id_attrs` and corresponding documentation
|
||||
- [ ] `__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
|
||||
- [ ] Link new and existing constants in docstrings instead of hard coded number and strings
|
||||
- [ ] Add new message types to `Message.effective_attachment`
|
||||
- [ ] Added new handlers for new update types
|
||||
- [ ] 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_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`
|
||||
|
||||
@@ -7,7 +7,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v7
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
# PRs never get stale
|
||||
days-before-stale: 3
|
||||
|
||||
+21
-34
File diff suppressed because one or more lines are too long
@@ -23,21 +23,22 @@ jobs:
|
||||
- name: Install Pyright
|
||||
run: |
|
||||
python -W ignore -m pip install pyright~=1.1.291
|
||||
- name: Get PR Completeness
|
||||
# Must run before base completeness, as base completeness will checkout the base branch
|
||||
# And we can't go back to the PR branch after that in case the PR is coming from a fork
|
||||
run: |
|
||||
pip install . -U
|
||||
pyright --verifytypes telegram --ignoreexternal --outputjson > pr.json || true
|
||||
pyright --verifytypes telegram --ignoreexternal > pr.readable || true
|
||||
- name: Get Base Completeness
|
||||
run: |
|
||||
git checkout ${{ github.base_ref }}
|
||||
pip install . -U
|
||||
pyright --verifytypes telegram --ignoreexternal --outputjson > base.json || true
|
||||
- name: Get PR Completeness
|
||||
run: |
|
||||
git checkout ${{ github.head_ref }}
|
||||
pip install . -U
|
||||
pyright --verifytypes telegram --ignoreexternal --outputjson > pr.json || true
|
||||
pyright --verifytypes telegram --ignoreexternal > pr.readable || true
|
||||
- name: Compare Completeness
|
||||
uses: jannekem/run-python-script-action@v1
|
||||
with:
|
||||
script: |
|
||||
script: |
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
@@ -48,21 +49,21 @@ jobs:
|
||||
pr = float(
|
||||
json.load(open("pr.json", "rb"))["typeCompleteness"]["completenessScore"]
|
||||
)
|
||||
base_text = f"After this PR, type completeness will be {round(pr, 3)}."
|
||||
if pr < (base - 0.1):
|
||||
text = f"This PR decreases type completeness by {round(base - pr, 3)}. ❌"
|
||||
base_text = f"This PR changes type completeness from {round(base, 3)} to {round(pr, 3)}."
|
||||
if pr < (base - 0.001):
|
||||
text = f"{base_text} ❌"
|
||||
set_summary(text)
|
||||
print(Path("pr.readable").read_text(encoding="utf-8"))
|
||||
error(f"{text}\n{base_text}")
|
||||
error(text)
|
||||
exit(1)
|
||||
elif pr > (base + 0.1):
|
||||
text = f"This PR increases type completeness by {round(pr - base, 3)}. ✨"
|
||||
elif pr > (base + 0.001):
|
||||
text = f"{base_text} ✨"
|
||||
set_summary(text)
|
||||
if pr < 1:
|
||||
print(Path("pr.readable").read_text(encoding="utf-8"))
|
||||
print(f"{text}\n{base_text}")
|
||||
print(text)
|
||||
else:
|
||||
text = f"This PR does not change type completeness by more than 0.1. ✅"
|
||||
text = f"{base_text} This is less than 0.1 percentage points. ✅"
|
||||
set_summary(text)
|
||||
print(Path("pr.readable").read_text(encoding="utf-8"))
|
||||
print(f"{text}\n{base_text}")
|
||||
print(text)
|
||||
|
||||
@@ -51,6 +51,8 @@ nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
.coveralls.yml
|
||||
.testmondata
|
||||
.testmondata-journal
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
+10
-10
@@ -9,7 +9,7 @@ ci:
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.1.0
|
||||
rev: 23.3.0
|
||||
hooks:
|
||||
- id: black
|
||||
args:
|
||||
@@ -20,7 +20,7 @@ repos:
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/PyCQA/pylint
|
||||
rev: v2.16.1
|
||||
rev: v3.0.0a6
|
||||
hooks:
|
||||
- id: pylint
|
||||
files: ^(telegram|examples)/.*\.py$
|
||||
@@ -33,12 +33,12 @@ repos:
|
||||
additional_dependencies:
|
||||
- httpx~=0.23.3
|
||||
- tornado~=6.2
|
||||
- APScheduler~=3.10.0
|
||||
- APScheduler~=3.10.1
|
||||
- cachetools~=5.3.0
|
||||
- aiolimiter~=1.0.0
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v0.991
|
||||
rev: v1.2.0
|
||||
hooks:
|
||||
- id: mypy
|
||||
name: mypy-ptb
|
||||
@@ -49,7 +49,7 @@ repos:
|
||||
- types-cachetools
|
||||
- httpx~=0.23.3
|
||||
- tornado~=6.2
|
||||
- APScheduler~=3.10.0
|
||||
- APScheduler~=3.10.1
|
||||
- cachetools~=5.3.0
|
||||
- aiolimiter~=1.0.0
|
||||
- . # this basically does `pip install -e .`
|
||||
@@ -61,11 +61,11 @@ repos:
|
||||
- --follow-imports=silent
|
||||
additional_dependencies:
|
||||
- tornado~=6.2
|
||||
- APScheduler~=3.10.0
|
||||
- APScheduler~=3.10.1
|
||||
- cachetools~=5.3.0
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.3.1
|
||||
rev: v3.3.2
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
files: ^(telegram|examples|tests|docs)/.*\.py$
|
||||
@@ -80,14 +80,14 @@ repos:
|
||||
- --diff
|
||||
- --check
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: 'v0.0.243'
|
||||
rev: 'v0.0.263'
|
||||
hooks:
|
||||
- id: ruff
|
||||
name: ruff
|
||||
files: ^(telegram|examples)/.*\.py$
|
||||
files: ^(telegram|examples|tests)/.*\.py$
|
||||
additional_dependencies:
|
||||
- httpx~=0.23.3
|
||||
- tornado~=6.2
|
||||
- APScheduler~=3.10.0
|
||||
- APScheduler~=3.10.1
|
||||
- cachetools~=5.3.0
|
||||
- aiolimiter~=1.0.0
|
||||
|
||||
@@ -72,6 +72,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `Li-aung Yip <https://github.com/LiaungYip>`_
|
||||
- `Loo Zheng Yuan <https://github.com/loozhengyuan>`_
|
||||
- `LRezende <https://github.com/lrezende>`_
|
||||
- `Luca Bellanti <https://github.com/Trifase>`_
|
||||
- `macrojames <https://github.com/macrojames>`_
|
||||
- `Matheus Lemos <https://github.com/mlemosf>`_
|
||||
- `Michael Dix <https://github.com/Eisberge>`_
|
||||
@@ -100,6 +101,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `Riko Naka <https://github.com/rikonaka>`_
|
||||
- `Rizlas <https://github.com/rizlas>`_
|
||||
- `Sahil Sharma <https://github.com/sahilsharma811>`_
|
||||
- `Sam Mosleh <https://github.com/sam-mosleh>`_
|
||||
- `Sascha <https://github.com/saschalalala>`_
|
||||
- `Shelomentsev D <https://github.com/shelomentsevd>`_
|
||||
- `Shivam Saini <https://github.com/shivamsn97>`_
|
||||
|
||||
+124
-1
@@ -1,7 +1,130 @@
|
||||
.. _ptb-changelog:
|
||||
|
||||
=========
|
||||
Changelog
|
||||
=========
|
||||
|
||||
Version 20.3
|
||||
============
|
||||
*Released 2023-05-07*
|
||||
|
||||
This is the technical changelog for version 20.3. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Major Changes
|
||||
-------------
|
||||
|
||||
- Full support for API 6.7 (`#3673`_)
|
||||
- Add a Stability Policy (`#3622`_)
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
- Add ``Application.mark_data_for_update_persistence`` (`#3607`_)
|
||||
- Make ``Message.link`` Point to Thread View Where Possible (`#3640`_)
|
||||
- Localize Received ``datetime`` Objects According to ``Defaults.tzinfo`` (`#3632`_)
|
||||
|
||||
Minor Changes, Documentation Improvements and CI
|
||||
------------------------------------------------
|
||||
|
||||
- Empower ``ruff`` (`#3594`_)
|
||||
- Drop Usage of ``sys.maxunicode`` (`#3630`_)
|
||||
- Add String Representation for ``RequestParameter`` (`#3634`_)
|
||||
- Stabilize CI by Rerunning Failed Tests (`#3631`_)
|
||||
- Give Loggers Better Names (`#3623`_)
|
||||
- Add Logging for Invalid JSON Data in ``BasePersistence.parse_json_payload`` (`#3668`_)
|
||||
- Improve Warning Categories & Stacklevels (`#3674`_)
|
||||
- Stabilize ``test_delete_sticker_set`` (`#3685`_)
|
||||
- Shield Update Fetcher Task in ``Application.start`` (`#3657`_)
|
||||
- Recover 100% Type Completeness (`#3676`_)
|
||||
- Documentation Improvements (`#3628`_, `#3636`_, `#3694`_)
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
- Bump ``actions/stale`` from 7 to 8 (`#3644`_)
|
||||
- Bump ``furo`` from 2023.3.23 to 2023.3.27 (`#3643`_)
|
||||
- ``pre-commit`` autoupdate (`#3646`_, `#3688`_)
|
||||
- Remove Deprecated ``codecov`` Package from CI (`#3664`_)
|
||||
- Bump ``sphinx-copybutton`` from 0.5.1 to 0.5.2 (`#3662`_)
|
||||
- Update ``httpx`` requirement from ~=0.23.3 to ~=0.24.0 (`#3660`_)
|
||||
- Bump ``pytest`` from 7.2.2 to 7.3.1 (`#3661`_)
|
||||
|
||||
.. _`#3673`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3673
|
||||
.. _`#3622`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3622
|
||||
.. _`#3607`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3607
|
||||
.. _`#3640`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3640
|
||||
.. _`#3632`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3632
|
||||
.. _`#3594`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3594
|
||||
.. _`#3630`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3630
|
||||
.. _`#3634`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3634
|
||||
.. _`#3631`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3631
|
||||
.. _`#3623`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3623
|
||||
.. _`#3668`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3668
|
||||
.. _`#3674`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3674
|
||||
.. _`#3685`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3685
|
||||
.. _`#3657`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3657
|
||||
.. _`#3676`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3676
|
||||
.. _`#3628`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3628
|
||||
.. _`#3636`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3636
|
||||
.. _`#3694`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3694
|
||||
.. _`#3644`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3644
|
||||
.. _`#3643`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3643
|
||||
.. _`#3646`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3646
|
||||
.. _`#3688`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3688
|
||||
.. _`#3664`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3664
|
||||
.. _`#3662`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3662
|
||||
.. _`#3660`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3660
|
||||
.. _`#3661`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3661
|
||||
|
||||
Version 20.2
|
||||
============
|
||||
*Released 2023-03-25*
|
||||
|
||||
This is the technical changelog for version 20.2. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Major Changes
|
||||
-------------
|
||||
- Full Support for API 6.6 (`#3584`_)
|
||||
- Revert to HTTP/1.1 as Default and make HTTP/2 an Optional Dependency (`#3576`_)
|
||||
|
||||
Minor Changes, Documentation Improvements and CI
|
||||
------------------------------------------------
|
||||
- Documentation Improvements (`#3565`_, `#3600`_)
|
||||
- Handle Symbolic Links in ``was_called_by`` (`#3552`_)
|
||||
- Tidy Up Tests Directory (`#3553`_)
|
||||
- Enhance ``Application.create_task`` (`#3543`_)
|
||||
- Make Type Completeness Workflow Usable for ``PRs`` from Forks (`#3551`_)
|
||||
- Refactor and Overhaul the Test Suite (`#3426`_)
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
- Bump ``pytest-asyncio`` from 0.20.3 to 0.21.0 (`#3624`_)
|
||||
- Bump ``furo`` from 2022.12.7 to 2023.3.23 (`#3625`_)
|
||||
- Bump ``pytest-xdist`` from 3.2.0 to 3.2.1 (`#3606`_)
|
||||
- ``pre-commit`` autoupdate (`#3577`_)
|
||||
- Update ``apscheduler`` requirement from ~=3.10.0 to ~=3.10.1 (`#3572`_)
|
||||
- Bump ``pytest`` from 7.2.1 to 7.2.2 (`#3573`_)
|
||||
- Bump ``pytest-xdist`` from 3.1.0 to 3.2.0 (`#3550`_)
|
||||
- Bump ``sphinxcontrib-mermaid`` from 0.7.1 to 0.8 (`#3549`_)
|
||||
|
||||
.. _`#3584`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3584
|
||||
.. _`#3576`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3576
|
||||
.. _`#3565`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3565
|
||||
.. _`#3600`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3600
|
||||
.. _`#3552`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3552
|
||||
.. _`#3553`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3553
|
||||
.. _`#3543`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3543
|
||||
.. _`#3551`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3551
|
||||
.. _`#3426`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3426
|
||||
.. _`#3624`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3624
|
||||
.. _`#3625`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3625
|
||||
.. _`#3606`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3606
|
||||
.. _`#3577`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3577
|
||||
.. _`#3572`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3572
|
||||
.. _`#3573`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3573
|
||||
.. _`#3550`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3550
|
||||
.. _`#3549`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3549
|
||||
|
||||
Version 20.1
|
||||
============
|
||||
*Released 2023-02-09*
|
||||
@@ -2108,7 +2231,7 @@ Changes
|
||||
- Lots of small improvements to our tests and documentation.
|
||||
|
||||
|
||||
.. _`see docs`: https://docs.python-telegram-bot.org/en/stable/telegram.ext.dispatcher.html#telegram.ext.Dispatcher.add_handler
|
||||
.. _`see docs`: https://docs.python-telegram-bot.org/en/v13.11/telegram.ext.dispatcher.html?highlight=Dispatcher.add_handler#telegram.ext.Dispatcher.add_handler
|
||||
.. _`#777`: https://github.com/python-telegram-bot/python-telegram-bot/pull/777
|
||||
.. _`#806`: https://github.com/python-telegram-bot/python-telegram-bot/pull/806
|
||||
.. _`#766`: https://github.com/python-telegram-bot/python-telegram-bot/pull/766
|
||||
|
||||
+8
-8
@@ -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.5-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.7-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
:target: https://app.codacy.com/gh/python-telegram-bot/python-telegram-bot/dashboard
|
||||
:alt: Code quality: Codacy
|
||||
|
||||
.. image:: https://deepsource.io/gh/python-telegram-bot/python-telegram-bot.svg/?label=active+issues
|
||||
:target: https://deepsource.io/gh/python-telegram-bot/python-telegram-bot/?ref=repository-badge
|
||||
.. image:: https://app.deepsource.com/gh/python-telegram-bot/python-telegram-bot.svg/?label=active+issues
|
||||
:target: https://app.deepsource.com/gh/python-telegram-bot/python-telegram-bot/?ref=repository-badge
|
||||
:alt: Code quality: DeepSource
|
||||
|
||||
.. image:: https://results.pre-commit.ci/badge/github/python-telegram-bot/python-telegram-bot/master.svg
|
||||
@@ -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.5** are supported.
|
||||
All types and methods of the Telegram Bot API **6.7** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
@@ -135,9 +135,8 @@ As these features are *optional*, the corresponding 3rd party dependencies are n
|
||||
Instead, they are listed as optional dependencies.
|
||||
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
|
||||
|
||||
The only required dependency is `httpx[http2] ~= 0.23.3 <https://www.python-httpx.org>`_ for
|
||||
``telegram.request.HTTPXRequest``, the default networking backend. By default, HTTP/2 is used, as it
|
||||
provides greater performance and stability, specially for concurrent requests.
|
||||
The only required dependency is `httpx ~= 0.23.3 <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 (optional) dependencies.
|
||||
@@ -151,10 +150,11 @@ PTB can be installed with optional dependencies:
|
||||
|
||||
* ``pip install python-telegram-bot[passport]`` installs the `cryptography>=39.0.1 <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] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
|
||||
* ``pip install python-telegram-bot[http2]`` installs `httpx[http2] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to use HTTP/2.
|
||||
* ``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.3.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.10.0 <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``.
|
||||
* ``pip install python-telegram-bot[job-queue]`` installs the `APScheduler~=3.10.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]``.
|
||||
|
||||
|
||||
+7
-7
@@ -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.5-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.7-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
:target: https://app.codacy.com/gh/python-telegram-bot/python-telegram-bot/dashboard
|
||||
:alt: Code quality: Codacy
|
||||
|
||||
.. image:: https://deepsource.io/gh/python-telegram-bot/python-telegram-bot.svg/?label=active+issues
|
||||
:target: https://deepsource.io/gh/python-telegram-bot/python-telegram-bot/?ref=repository-badge
|
||||
.. image:: https://app.deepsource.com/gh/python-telegram-bot/python-telegram-bot.svg/?label=active+issues
|
||||
:target: https://app.deepsource.com/gh/python-telegram-bot/python-telegram-bot/?ref=repository-badge
|
||||
:alt: Code quality: DeepSource
|
||||
|
||||
.. image:: https://results.pre-commit.ci/badge/github/python-telegram-bot/python-telegram-bot/master.svg
|
||||
@@ -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.5** are supported.
|
||||
All types and methods of the Telegram Bot API **6.7** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
@@ -136,9 +136,8 @@ As these features are *optional*, the corresponding 3rd party dependencies are n
|
||||
Instead, they are listed as optional dependencies.
|
||||
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
|
||||
|
||||
The only required dependency is `httpx[http2] ~= 0.23.3 <https://www.python-httpx.org>`_ for
|
||||
``telegram.request.HTTPXRequest``, the default networking backend. By default, HTTP/2 is used, as
|
||||
it provides greater performance and stability, specially for concurrent requests.
|
||||
The only required dependency is `httpx ~= 0.23.3 <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 (optional) dependencies.
|
||||
@@ -152,6 +151,7 @@ PTB can be installed with optional dependencies:
|
||||
|
||||
* ``pip install python-telegram-bot-raw[passport]`` installs the `cryptography>=39.0.1 <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.
|
||||
* ``pip install python-telegram-bot[http2]`` installs `httpx[http2] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to use HTTP/2.
|
||||
|
||||
To install multiple optional dependencies, separate them by commas, e.g. ``pip install python-telegram-bot-raw[passport,socks]``.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
sphinx==6.1.3
|
||||
sphinx-pypi-upload
|
||||
furo==2022.12.7
|
||||
furo==2023.3.27
|
||||
git+https://github.com/harshil21/furo-sphinx-search@01efc7be422d7dc02390aab9be68d6f5ce1a5618#egg=furo-sphinx-search
|
||||
sphinx-paramlinks==0.5.4
|
||||
sphinxcontrib-mermaid==0.7.1
|
||||
sphinx-copybutton==0.5.1
|
||||
sphinxcontrib-mermaid==0.8.1
|
||||
sphinx-copybutton==0.5.2
|
||||
|
||||
+2
-2
@@ -21,9 +21,9 @@ author = "Leandro Toledo"
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = "20.1" # telegram.__version__[:3]
|
||||
version = "20.3" # telegram.__version__[:3]
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = "20.1" # telegram.__version__
|
||||
release = "20.3" # telegram.__version__
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
needs_sphinx = "6.1.3"
|
||||
|
||||
@@ -8,7 +8,7 @@ aspect of the Telegram Bot API while others focus on one of the
|
||||
mechanics of this library. Except for the
|
||||
:any:`examples.rawapibot` example, they all use the high-level
|
||||
framework this library provides with the
|
||||
:any:`telegram.ext <telegram.ext>` submodule.
|
||||
:mod:`telegram.ext` submodule.
|
||||
|
||||
All examples are licensed under the `CC0
|
||||
License <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/LICENSE.txt>`__
|
||||
|
||||
@@ -157,6 +157,23 @@
|
||||
- Used for getting the number of members in a chat
|
||||
* - :meth:`~telegram.Bot.get_chat_member`
|
||||
- Used for getting a member of a chat
|
||||
* - :meth:`~telegram.Bot.leave_chat`
|
||||
- Used for leaving a chat
|
||||
|
||||
.. raw:: html
|
||||
|
||||
</details>
|
||||
<br>
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<details>
|
||||
<summary>Bot settings</summary>
|
||||
|
||||
.. list-table::
|
||||
:align: left
|
||||
:widths: 1 4
|
||||
|
||||
* - :meth:`~telegram.Bot.set_my_commands`
|
||||
- Used for setting the list of commands
|
||||
* - :meth:`~telegram.Bot.delete_my_commands`
|
||||
@@ -171,8 +188,18 @@
|
||||
- Used for obtaining the menu button of a private chat or the default menu button
|
||||
* - :meth:`~telegram.Bot.set_chat_menu_button`
|
||||
- Used for setting the menu button of a private chat or the default menu button
|
||||
* - :meth:`~telegram.Bot.leave_chat`
|
||||
- Used for leaving a chat
|
||||
* - :meth:`~telegram.Bot.set_my_description`
|
||||
- Used for setting the description of the bot
|
||||
* - :meth:`~telegram.Bot.get_my_description`
|
||||
- Used for obtaining the description of the bot
|
||||
* - :meth:`~telegram.Bot.set_my_short_description`
|
||||
- Used for setting the short description of the bot
|
||||
* - :meth:`~telegram.Bot.get_my_short_description`
|
||||
- Used for obtaining the short description of the bot
|
||||
* - :meth:`~telegram.Bot.set_my_name`
|
||||
- Used for setting the name of the bot
|
||||
* - :meth:`~telegram.Bot.get_my_name`
|
||||
- Used for obtaining the name of the bot
|
||||
|
||||
.. raw:: html
|
||||
|
||||
@@ -194,14 +221,26 @@
|
||||
- Used for deleting a sticker from a set
|
||||
* - :meth:`~telegram.Bot.create_new_sticker_set`
|
||||
- Used for creating a new sticker set
|
||||
* - :meth:`~telegram.Bot.delete_sticker_set`
|
||||
- Used for deleting a sticker set made by a bot
|
||||
* - :meth:`~telegram.Bot.set_chat_sticker_set`
|
||||
- Used for setting a sticker set
|
||||
- Used for setting a sticker set of a chat
|
||||
* - :meth:`~telegram.Bot.delete_chat_sticker_set`
|
||||
- Used for deleting the set sticker set
|
||||
- Used for deleting the set sticker set of a chat
|
||||
* - :meth:`~telegram.Bot.set_sticker_position_in_set`
|
||||
- Used for moving a sticker's position in the set
|
||||
* - :meth:`~telegram.Bot.set_sticker_set_title`
|
||||
- Used for setting the title of a sticker set
|
||||
* - :meth:`~telegram.Bot.set_sticker_emoji_list`
|
||||
- Used for setting the emoji list of a sticker
|
||||
* - :meth:`~telegram.Bot.set_sticker_keywords`
|
||||
- Used for setting the keywords of a sticker
|
||||
* - :meth:`~telegram.Bot.set_sticker_mask_position`
|
||||
- Used for setting the mask position of a mask sticker
|
||||
* - :meth:`~telegram.Bot.set_sticker_set_thumb`
|
||||
- Used for setting the thumbnail of a sticker set
|
||||
* - :meth:`~telegram.Bot.set_custom_emoji_sticker_set_thumbnail`
|
||||
- Used for setting the thumbnail of a custom emoji sticker set
|
||||
* - :meth:`~telegram.Bot.get_sticker_set`
|
||||
- Used for getting a sticker set
|
||||
* - :meth:`~telegram.Bot.upload_sticker_file`
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
:hidden:
|
||||
:caption: Project
|
||||
|
||||
stability_policy
|
||||
changelog
|
||||
coc
|
||||
contributing
|
||||
testing
|
||||
Website <https://python-telegram-bot.org>
|
||||
GitHub Repository <https://github.com/python-telegram-bot/python-telegram-bot/>
|
||||
Telegram Channel <https://t.me/pythontelegrambotchannel/>
|
||||
Telegram User Group <https://t.me/pythontelegrambotgroup/>
|
||||
contributing
|
||||
coc
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
Stability Policy
|
||||
================
|
||||
|
||||
.. important::
|
||||
|
||||
This stability policy is in place since version 20.3.
|
||||
While earlier versions of ``python-telegram-bot`` also had stable interfaces, they had no explicit stability policy and hence did not follow the rules outlined below in all detail.
|
||||
Please also refer to the :ref:`changelog <ptb-changelog>`.
|
||||
|
||||
.. caution::
|
||||
|
||||
Large parts of the :mod:`telegram` package are the Python representations of the Telegram Bot API, whose stability policy PTB can not influence.
|
||||
This policy hence includes some special cases for those parts.
|
||||
|
||||
What does this policy cover?
|
||||
----------------------------
|
||||
|
||||
This policy includes any API or behavior that is covered in this documentation.
|
||||
This covers both the :mod:`telegram` package and the :mod:`telegram.ext` package.
|
||||
|
||||
What doesn't this policy cover?
|
||||
-------------------------------
|
||||
|
||||
Introduction of new features or changes of flavors of comparable behavior (e.g. the default for the HTTP protocol version being used) are not covered by this policy.
|
||||
|
||||
The internal structure of classes in PTB, i.e. things like the result of ``dir(obj))`` or the contents of ``obj.__dict__``, is not covered by this policy.
|
||||
|
||||
Objects are in general not guaranteed to be pickleable (unless stated otherwise) and pickled objects from one version of PTB may not be loadable in future versions.
|
||||
We may provide a way to convert pickled objects from one version to another, but this is not guaranteed.
|
||||
|
||||
Functionality that is part of PTBs API but is explicitly documented as not being intended to be used directly by users (e.g. :meth:`telegram.request.BaseRequest.do_request`) may change.
|
||||
This also applies to functions or attributes marked as final in the sense of `PEP 591 <https://www.python.org/dev/peps/pep-0591/>`__.
|
||||
|
||||
PTB has dependencies to third-party packages.
|
||||
The versions that PTB uses of these third-party packages may change if that does not affect PTBs public API.
|
||||
|
||||
PTB does not give guarantees about which Python versions are supported.
|
||||
In general, we will try to support all Python versions that have not yet reached their end of life, but we reserve ourselves the option to drop support for Python versions earlier if that benefits the advancement of the library.
|
||||
|
||||
.. _bot-api-functionality-1:
|
||||
|
||||
Bot API Functionality
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Comparison of equality of instances of the classes in the :mod:`telegram` package is subject to change and the PTB team will update the behavior to best reflect updates in the Bot API.
|
||||
Changes in this regard will be documented in the affected classes.
|
||||
Note that equality comparison with objects that where serialized by an older version of PTB may hence give unexpected results.
|
||||
|
||||
When the order of arguments of the Bot API methods changes or they become optional/mandatory due to changes in the Bot API, PTB will always try to reflect these changes.
|
||||
While we try to make such changes backward compatible, this is not always possible or only with significant effort.
|
||||
In such cases we will find a trade-off between backward compatibility and fully complying with the Bot API, which may result in breaking changes.
|
||||
We highly recommend using keyword arguments, which can help make such changes non-breaking on your end.
|
||||
|
||||
..
|
||||
We have documented a few common cases and possible backwards compatible solutions in the wiki as a reference for the dev team: https://github.com/python-telegram-bot/python-telegram-bot/wiki/Bot-API-Backward-Compatibility
|
||||
|
||||
When the Bot API changes attributes of classes, the method :meth:`telegram.TelegramObject.to_dict` will change as necessary to reflect these changes.
|
||||
In particular, attributes deprecated by Telegram will be removed from the returned dictionary.
|
||||
Deprecated attributes that are still passed by Telegram will be available in the :attr:`~telegram.TelegramObject.api_kwargs` dictionary as long as PTB can support that with feasible effort.
|
||||
Since attributes of the classes in the :mod:`telegram` package are not writable, we may change them to properties where appropriate.
|
||||
|
||||
Development Versions
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Pre-releases marked as alpha, beta or release candidate are not covered by this policy.
|
||||
Before a feature is in a stable release, i.e. the feature was merged into the ``master`` branch but not released yet (or only in a pre-release), it is not covered by this policy either and may change.
|
||||
|
||||
Security
|
||||
~~~~~~~~
|
||||
|
||||
We make exceptions from our stability policy for security.
|
||||
We will violate this policy as necessary in order to resolve a security issue or harden PTB against a possible attack.
|
||||
|
||||
Versioning
|
||||
----------
|
||||
|
||||
PTB uses a versioning scheme that roughly follows `https://semver.org/ <https://semver.org/>`_, although it may not be quite as strict.
|
||||
|
||||
Given a version of PTB X.Y.Z,
|
||||
|
||||
- X indicates the major version number.
|
||||
This is incremented when backward incompatible changes are introduced.
|
||||
- Y indicates the minor version number.
|
||||
This is incremented when new functionality or backward compatible changes are introduced by PTB.
|
||||
*This is also incremented when PTB adds support for a new Bot API version, which may include backward incompatible changes in some cases as outlined* :ref:`below <bot-api-versioning>`.
|
||||
- Z is the patch version.
|
||||
This is incremented if backward compatible bug fixes or smaller changes are introduced.
|
||||
If this number is 0, it can be omitted, i.e. we just write X.Y instead of X.Y.0.
|
||||
|
||||
Deprecation
|
||||
~~~~~~~~~~~
|
||||
|
||||
From time to time we will want to change the behavior of an API or remove it entirely, or we do so to comply with changes in the Telegram Bot API.
|
||||
In those cases, we follow a deprecation schedule as detailed below.
|
||||
|
||||
Functionality is marked as deprecated by a corresponding note in the release notes and the documentation.
|
||||
Where possible, a :class:`~telegram.warnings.PTBDeprecationWarning` is issued when deprecated functionality is used, but this is not mandatory.
|
||||
|
||||
From time to time, we may decide to deprecate an API that is particularly widely used.
|
||||
In these cases, we may decide to provide an extended deprecation period, at our discretion.
|
||||
|
||||
With version 20.0.0, PTB introduced major structural breaking changes without the above deprecation period.
|
||||
Should a similarly big change ever be deemed necessary again by the development team and should a deprecation period prove too much additional effort, this violation of the stability policy will be announced well ahead of the release in our channel, `as was done for v20 <https://t.me/pythontelegrambotchannel/94>`_.
|
||||
|
||||
Non-Bot API Functionality
|
||||
#########################
|
||||
|
||||
Starting with version 20.3, deprecated functionality will stay available for the current and the next major version.
|
||||
For example:
|
||||
|
||||
- In PTB v20.1.1 the feature exists
|
||||
- In PTB v20.1.2 or v20.2.0 the feature is marked as deprecated
|
||||
- In PTB v21.*.* the feature is marked as deprecated
|
||||
- In PTB v22.0 the feature is removed or changed
|
||||
|
||||
.. _bot-api-versioning:
|
||||
|
||||
Bot API Functionality
|
||||
#####################
|
||||
|
||||
As PTB has no control over deprecations introduced by Telegram and the schedule of these deprecations rarely coincides with PTBs deprecation schedule, we have a special policy for Bot API functionality.
|
||||
|
||||
Starting with 20.3, deprecated Bot API functionality will stay available for the current and the next major version of PTB *or* until the next version of the Bot API.
|
||||
More precisely, two cases are possible, for which we show examples below.
|
||||
|
||||
Case 1
|
||||
^^^^^^
|
||||
|
||||
- In PTB v20.1 the feature exists
|
||||
- Bot API version 6.6 is released and deprecates the feature
|
||||
- PTB v20.2 adds support for Bot API 6.6 and the feature is
|
||||
marked as deprecated
|
||||
- In PTB v21.0 the feature is removed or changed
|
||||
|
||||
Case 2
|
||||
^^^^^^
|
||||
|
||||
- In PTB v20.1 the feature exists
|
||||
- Bot API version 6.6 is released and deprecates the feature
|
||||
- PTB v20.2 adds support for Bot API version 6.6 and the feature is marked as deprecated
|
||||
- In PTB v20.2.* and v20.3.* the feature is marked as deprecated
|
||||
- Bot API version 6.7 is released
|
||||
- PTB v20.4 adds support for Bot API version 6.7 and the feature is removed or changed
|
||||
@@ -15,6 +15,9 @@ Available Types
|
||||
telegram.botcommandscopechatadministrators
|
||||
telegram.botcommandscopechatmember
|
||||
telegram.botcommandscopedefault
|
||||
telegram.botdescription
|
||||
telegram.botname
|
||||
telegram.botshortdescription
|
||||
telegram.callbackquery
|
||||
telegram.chat
|
||||
telegram.chatadministratorrights
|
||||
@@ -53,6 +56,7 @@ Available Types
|
||||
telegram.inputmediadocument
|
||||
telegram.inputmediaphoto
|
||||
telegram.inputmediavideo
|
||||
telegram.inputsticker
|
||||
telegram.keyboardbutton
|
||||
telegram.keyboardbuttonpolltype
|
||||
telegram.keyboardbuttonrequestchat
|
||||
@@ -75,6 +79,7 @@ Available Types
|
||||
telegram.replykeyboardmarkup
|
||||
telegram.replykeyboardremove
|
||||
telegram.sentwebappmessage
|
||||
telegram.switchinlinequerychosenchat
|
||||
telegram.telegramobject
|
||||
telegram.update
|
||||
telegram.user
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
BotDescription
|
||||
==============
|
||||
|
||||
.. autoclass:: telegram.BotDescription
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
BotName
|
||||
=======
|
||||
|
||||
.. autoclass:: telegram.BotName
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
BotShortDescription
|
||||
===================
|
||||
|
||||
.. autoclass:: telegram.BotShortDescription
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -1,6 +1,8 @@
|
||||
telegram.ext package
|
||||
====================
|
||||
|
||||
.. automodule:: telegram.ext
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ Inline Mode
|
||||
telegram.inlinequeryresultlocation
|
||||
telegram.inlinequeryresultmpeg4gif
|
||||
telegram.inlinequeryresultphoto
|
||||
telegram.inlinequeryresultsbutton
|
||||
telegram.inlinequeryresultvenue
|
||||
telegram.inlinequeryresultvideo
|
||||
telegram.inlinequeryresultvoice
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
InlineQueryResultsButton
|
||||
========================
|
||||
|
||||
.. autoclass:: telegram.InlineQueryResultsButton
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
InputSticker
|
||||
============
|
||||
|
||||
.. autoclass:: telegram.InputSticker
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
SwitchInlineQueryChosenChat
|
||||
===========================
|
||||
|
||||
.. autoclass:: telegram.SwitchInlineQueryChosenChat
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1 @@
|
||||
.. include:: ../../tests/README.rst
|
||||
@@ -14,6 +14,10 @@
|
||||
|
||||
.. |thumbdocstringnopath| replace:: |thumbdocstringbase| |uploadinputnopath|
|
||||
|
||||
.. |thumbargumentdeprecation| replace:: As of Bot API 6.6 this argument is deprecated in favor of
|
||||
|
||||
.. |thumbattributedeprecation| replace:: As of Bot API 6.6 this attribute is deprecated in favor of
|
||||
|
||||
.. |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.
|
||||
@@ -51,3 +55,5 @@
|
||||
.. |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``.
|
||||
|
||||
.. |datetime_localization| replace:: The default timezone of the bot is used for localization, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used.
|
||||
|
||||
@@ -103,13 +103,12 @@ async def track_chats(update: Update, context: ContextTypes.DEFAULT_TYPE) -> Non
|
||||
elif was_member and not is_member:
|
||||
logger.info("%s removed the bot from the group %s", cause_name, chat.title)
|
||||
context.bot_data.setdefault("group_ids", set()).discard(chat.id)
|
||||
else:
|
||||
if not was_member and is_member:
|
||||
logger.info("%s added the bot to the channel %s", cause_name, chat.title)
|
||||
context.bot_data.setdefault("channel_ids", set()).add(chat.id)
|
||||
elif was_member and not is_member:
|
||||
logger.info("%s removed the bot from the channel %s", cause_name, chat.title)
|
||||
context.bot_data.setdefault("channel_ids", set()).discard(chat.id)
|
||||
elif not was_member and is_member:
|
||||
logger.info("%s added the bot to the channel %s", cause_name, chat.title)
|
||||
context.bot_data.setdefault("channel_ids", set()).add(chat.id)
|
||||
elif was_member and not is_member:
|
||||
logger.info("%s removed the bot from the channel %s", cause_name, chat.title)
|
||||
context.bot_data.setdefault("channel_ids", set()).discard(chat.id)
|
||||
|
||||
|
||||
async def show_chats(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
|
||||
@@ -39,7 +39,7 @@ DEVELOPER_CHAT_ID = 123456789
|
||||
async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Log the error and send a telegram message to notify the developer."""
|
||||
# Log the error before we do anything else, so we can see it even if something breaks.
|
||||
logger.error(msg="Exception while handling an update:", exc_info=context.error)
|
||||
logger.error("Exception while handling an update:", exc_info=context.error)
|
||||
|
||||
# traceback.format_exception returns the usual python message about an exception, but as a
|
||||
# list of strings rather than a single string, so we have to join them together.
|
||||
|
||||
@@ -58,7 +58,7 @@ async def inline_query(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
|
||||
"""Handle the inline query. This is run when you type: @botusername <query>"""
|
||||
query = update.inline_query.query
|
||||
|
||||
if query == "":
|
||||
if not query: # empty query should not be handled
|
||||
return
|
||||
|
||||
results = [
|
||||
|
||||
+5
-2
@@ -48,6 +48,9 @@ logging.basicConfig(
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
TOTAL_VOTER_COUNT = 3
|
||||
|
||||
|
||||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Inform user about what this bot can do"""
|
||||
await update.message.reply_text(
|
||||
@@ -101,7 +104,7 @@ async def receive_poll_answer(update: Update, context: ContextTypes.DEFAULT_TYPE
|
||||
)
|
||||
answered_poll["answers"] += 1
|
||||
# Close poll after three participants voted
|
||||
if answered_poll["answers"] == 3:
|
||||
if answered_poll["answers"] == TOTAL_VOTER_COUNT:
|
||||
await context.bot.stop_poll(answered_poll["chat_id"], answered_poll["message_id"])
|
||||
|
||||
|
||||
@@ -123,7 +126,7 @@ async def receive_quiz_answer(update: Update, context: ContextTypes.DEFAULT_TYPE
|
||||
# the bot can receive closed poll updates we don't care about
|
||||
if update.poll.is_closed:
|
||||
return
|
||||
if update.poll.total_voter_count == 3:
|
||||
if update.poll.total_voter_count == TOTAL_VOTER_COUNT:
|
||||
try:
|
||||
quiz_data = context.bot_data[update.poll.id]
|
||||
# this means this poll answer update is from an old poll, we can't stop it then
|
||||
|
||||
@@ -7,6 +7,7 @@ on the telegram.ext bot framework.
|
||||
This program is dedicated to the public domain under the CC0 license.
|
||||
"""
|
||||
import asyncio
|
||||
import contextlib
|
||||
import logging
|
||||
from typing import NoReturn
|
||||
|
||||
@@ -72,7 +73,5 @@ async def echo(bot: Bot, update_id: int) -> int:
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
with contextlib.suppress(KeyboardInterrupt): # Ignore exception when Ctrl-C is pressed
|
||||
asyncio.run(main())
|
||||
except KeyboardInterrupt: # Ignore exception when Ctrl-C is pressed
|
||||
pass
|
||||
|
||||
@@ -18,8 +18,8 @@ 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]`
|
||||
To use the JobQueue, you must install PTB via
|
||||
`pip install python-telegram-bot[job-queue]`
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
@@ -9,3 +9,10 @@ line_length = 99
|
||||
[tool.ruff]
|
||||
line-length = 99
|
||||
target-version = "py37"
|
||||
show-fixes = true
|
||||
ignore = ["PLR2004", "PLR0911", "PLR0912", "PLR0913", "PLR0915"]
|
||||
select = ["E", "F", "I", "PL", "UP", "RUF", "PTH", "C4", "B", "PIE", "SIM", "RET", "RSE",
|
||||
"G", "ISC", "PT"]
|
||||
|
||||
[tool.ruff.per-file-ignores]
|
||||
"tests/*.py" = ["B018"]
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
pre-commit
|
||||
|
||||
pytest==7.2.1
|
||||
pytest-asyncio==0.20.3
|
||||
pytest-timeout==2.1.0 # used to timeout tests
|
||||
pytest-xdist==3.1.0 # xdist runs tests in parallel
|
||||
pre-commit # needed for pre-commit hooks in the git commit command
|
||||
|
||||
# For the test suite
|
||||
pytest==7.3.1
|
||||
pytest-asyncio==0.21.0 # needed because pytest doesn't come with native support for coroutines as tests
|
||||
pytest-xdist==3.2.1 # xdist runs tests in parallel
|
||||
flaky # Used for flaky tests (flaky decorator)
|
||||
beautifulsoup4 # used in test_official for parsing tg docs
|
||||
|
||||
wheel # required for building the wheels for releases
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
# versions and only increase the lower bound if necessary
|
||||
|
||||
httpx[socks] # socks
|
||||
httpx[http2] # http2
|
||||
cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=39.0.1 # passport
|
||||
aiolimiter~=1.0.0 # rate-limiter!ext
|
||||
|
||||
@@ -20,7 +21,7 @@ tornado~=6.2 # webhooks!ext
|
||||
# Cachetools and APS don't have a strict stability policy.
|
||||
# Let's be cautious for now.
|
||||
cachetools~=5.3.0 # callback-data!ext
|
||||
APScheduler~=3.10.0 # job-queue!ext
|
||||
APScheduler~=3.10.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
-2
@@ -6,5 +6,4 @@
|
||||
# versions and only increase the lower bound if necessary
|
||||
|
||||
# httpx has no stable release yet, so let's be cautious for now
|
||||
# HTTP/2 is more performant and stable than HTTP/1.1, specially for concurrent requests
|
||||
httpx[http2] ~= 0.23.3
|
||||
httpx ~= 0.24.0
|
||||
|
||||
@@ -36,7 +36,10 @@ filterwarnings =
|
||||
; Unfortunately due to https://github.com/pytest-dev/pytest/issues/8343 we can't have this here
|
||||
; and instead do a trick directly in tests/conftest.py
|
||||
; ignore::telegram.utils.deprecate.TelegramDeprecationWarning
|
||||
markers = dev: If you want to test a specific test, use this
|
||||
markers =
|
||||
dev: If you want to test a specific test, use this
|
||||
no_req
|
||||
req
|
||||
asyncio_mode = auto
|
||||
|
||||
[coverage:run]
|
||||
|
||||
@@ -37,6 +37,9 @@ __all__ = ( # Keep this alphabetically ordered
|
||||
"BotCommandScopeChatAdministrators",
|
||||
"BotCommandScopeChatMember",
|
||||
"BotCommandScopeDefault",
|
||||
"BotDescription",
|
||||
"BotName",
|
||||
"BotShortDescription",
|
||||
"CallbackGame",
|
||||
"CallbackQuery",
|
||||
"Chat",
|
||||
@@ -100,6 +103,7 @@ __all__ = ( # Keep this alphabetically ordered
|
||||
"InlineQueryResultLocation",
|
||||
"InlineQueryResultMpeg4Gif",
|
||||
"InlineQueryResultPhoto",
|
||||
"InlineQueryResultsButton",
|
||||
"InlineQueryResultVenue",
|
||||
"InlineQueryResultVideo",
|
||||
"InlineQueryResultVoice",
|
||||
@@ -114,6 +118,7 @@ __all__ = ( # Keep this alphabetically ordered
|
||||
"InputMediaPhoto",
|
||||
"InputMediaVideo",
|
||||
"InputMessageContent",
|
||||
"InputSticker",
|
||||
"InputTextMessageContent",
|
||||
"InputVenueMessageContent",
|
||||
"Invoice",
|
||||
@@ -166,6 +171,7 @@ __all__ = ( # Keep this alphabetically ordered
|
||||
"Sticker",
|
||||
"StickerSet",
|
||||
"SuccessfulPayment",
|
||||
"SwitchInlineQueryChosenChat",
|
||||
"TelegramObject",
|
||||
"Update",
|
||||
"User",
|
||||
@@ -200,6 +206,8 @@ from ._botcommandscope import (
|
||||
BotCommandScopeChatMember,
|
||||
BotCommandScopeDefault,
|
||||
)
|
||||
from ._botdescription import BotDescription, BotShortDescription
|
||||
from ._botname import BotName
|
||||
from ._callbackquery import CallbackQuery
|
||||
from ._chat import Chat
|
||||
from ._chatadministratorrights import ChatAdministratorRights
|
||||
@@ -234,6 +242,7 @@ from ._files.inputmedia import (
|
||||
InputMediaPhoto,
|
||||
InputMediaVideo,
|
||||
)
|
||||
from ._files.inputsticker import InputSticker
|
||||
from ._files.location import Location
|
||||
from ._files.photosize import PhotoSize
|
||||
from ._files.sticker import MaskPosition, Sticker, StickerSet
|
||||
@@ -275,6 +284,7 @@ from ._inline.inlinequeryresultgif import InlineQueryResultGif
|
||||
from ._inline.inlinequeryresultlocation import InlineQueryResultLocation
|
||||
from ._inline.inlinequeryresultmpeg4gif import InlineQueryResultMpeg4Gif
|
||||
from ._inline.inlinequeryresultphoto import InlineQueryResultPhoto
|
||||
from ._inline.inlinequeryresultsbutton import InlineQueryResultsButton
|
||||
from ._inline.inlinequeryresultvenue import InlineQueryResultVenue
|
||||
from ._inline.inlinequeryresultvideo import InlineQueryResultVideo
|
||||
from ._inline.inlinequeryresultvoice import InlineQueryResultVoice
|
||||
@@ -331,6 +341,7 @@ from ._replykeyboardmarkup import ReplyKeyboardMarkup
|
||||
from ._replykeyboardremove import ReplyKeyboardRemove
|
||||
from ._sentwebappmessage import SentWebAppMessage
|
||||
from ._shared import ChatShared, UserShared
|
||||
from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
|
||||
from ._telegramobject import TelegramObject
|
||||
from ._update import Update
|
||||
from ._user import User
|
||||
|
||||
+1155
-192
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# 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 two objects that represent a Telegram bots (short) description."""
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class BotDescription(TelegramObject):
|
||||
"""This object represents the bot's description.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`description` is equal.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Args:
|
||||
description (:obj:`str`): The bot's description.
|
||||
|
||||
Attributes:
|
||||
description (:obj:`str`): The bot's description.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("description",)
|
||||
|
||||
def __init__(self, description: str, *, api_kwargs: JSONDict = None):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.description: str = description
|
||||
|
||||
self._id_attrs = (self.description,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
|
||||
class BotShortDescription(TelegramObject):
|
||||
"""This object represents the bot's short description.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`short_description` is equal.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Args:
|
||||
short_description (:obj:`str`): The bot's short description.
|
||||
|
||||
Attributes:
|
||||
short_description (:obj:`str`): The bot's short description.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("short_description",)
|
||||
|
||||
def __init__(self, short_description: str, *, api_kwargs: JSONDict = None):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.short_description: str = short_description
|
||||
|
||||
self._id_attrs = (self.short_description,)
|
||||
|
||||
self._freeze()
|
||||
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represent a Telegram bots name."""
|
||||
from typing import ClassVar
|
||||
|
||||
from telegram import constants
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class BotName(TelegramObject):
|
||||
"""This object represents the bot's name.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`name` is equal.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
|
||||
Args:
|
||||
name (:obj:`str`): The bot's name.
|
||||
|
||||
Attributes:
|
||||
name (:obj:`str`): The bot's name.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("name",)
|
||||
|
||||
def __init__(self, name: str, *, api_kwargs: JSONDict = None):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.name: str = name
|
||||
|
||||
self._id_attrs = (self.name,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
MAX_LENGTH: ClassVar[int] = constants.BotNameLimit.MAX_NAME_LENGTH
|
||||
""":const:`telegram.constants.BotNameLimit.MAX_NAME_LENGTH`"""
|
||||
@@ -1532,6 +1532,7 @@ class Chat(TelegramObject):
|
||||
caption_entities: Sequence["MessageEntity"] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -1572,6 +1573,7 @@ class Chat(TelegramObject):
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
|
||||
async def send_document(
|
||||
@@ -1588,6 +1590,7 @@ class Chat(TelegramObject):
|
||||
caption_entities: Sequence["MessageEntity"] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -1620,6 +1623,7 @@ class Chat(TelegramObject):
|
||||
pool_timeout=pool_timeout,
|
||||
parse_mode=parse_mode,
|
||||
thumb=thumb,
|
||||
thumbnail=thumbnail,
|
||||
api_kwargs=api_kwargs,
|
||||
disable_content_type_detection=disable_content_type_detection,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
@@ -1875,6 +1879,7 @@ class Chat(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
has_spoiler: bool = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -1916,6 +1921,7 @@ class Chat(TelegramObject):
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
|
||||
async def send_sticker(
|
||||
@@ -1927,6 +1933,7 @@ class Chat(TelegramObject):
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
emoji: str = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
@@ -1958,6 +1965,7 @@ class Chat(TelegramObject):
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
emoji=emoji,
|
||||
)
|
||||
|
||||
async def send_venue(
|
||||
@@ -2036,6 +2044,7 @@ class Chat(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
has_spoiler: bool = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2071,6 +2080,7 @@ class Chat(TelegramObject):
|
||||
parse_mode=parse_mode,
|
||||
supports_streaming=supports_streaming,
|
||||
thumb=thumb,
|
||||
thumbnail=thumbnail,
|
||||
api_kwargs=api_kwargs,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
caption_entities=caption_entities,
|
||||
@@ -2092,6 +2102,7 @@ class Chat(TelegramObject):
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2123,6 +2134,7 @@ class Chat(TelegramObject):
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
thumb=thumb,
|
||||
thumbnail=thumbnail,
|
||||
api_kwargs=api_kwargs,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
filename=filename,
|
||||
|
||||
@@ -22,7 +22,7 @@ from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.datetime import from_timestamp
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -54,6 +54,9 @@ class ChatInviteLink(TelegramObject):
|
||||
is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked.
|
||||
expire_date (:class:`datetime.datetime`, optional): Date when the link will expire or
|
||||
has been expired.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
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;
|
||||
:tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`-
|
||||
@@ -78,6 +81,9 @@ class ChatInviteLink(TelegramObject):
|
||||
is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked.
|
||||
expire_date (:class:`datetime.datetime`): Optional. Date when the link will expire or
|
||||
has been expired.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
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;
|
||||
:tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`-
|
||||
@@ -152,7 +158,10 @@ class ChatInviteLink(TelegramObject):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["creator"] = User.de_json(data.get("creator"), bot)
|
||||
data["expire_date"] = from_timestamp(data.get("expire_date", None))
|
||||
data["expire_date"] = from_timestamp(data.get("expire_date", None), tzinfo=loc_tzinfo)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -24,7 +24,7 @@ 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
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import JSONDict, ODVInput
|
||||
|
||||
@@ -41,7 +41,7 @@ class ChatJoinRequest(TelegramObject):
|
||||
Note:
|
||||
* Since Bot API 5.5, bots are allowed to contact users who sent a join request to a chat
|
||||
where the bot is an administrator with the
|
||||
:attr:`~telegram.ChatMemberAdministrator.can_invite_users` administrator right – even
|
||||
:attr:`~telegram.ChatMemberAdministrator.can_invite_users` administrator right - even
|
||||
if the user never interacted with the bot before.
|
||||
* Telegram does not guarantee that :attr:`from_user.id <from_user>` coincides with the
|
||||
``chat_id`` of the user. Please use :attr:`user_chat_id` to contact the user in
|
||||
@@ -56,6 +56,9 @@ class ChatJoinRequest(TelegramObject):
|
||||
chat (:class:`telegram.Chat`): Chat to which the request was sent.
|
||||
from_user (:class:`telegram.User`): User that sent the join request.
|
||||
date (:class:`datetime.datetime`): Date the request was sent.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
user_chat_id (:obj:`int`): Identifier of a private chat with the user who sent the join
|
||||
request. This number may have more than 32 significant bits and some programming
|
||||
languages may have difficulty/silent defects in interpreting it. But it has at most 52
|
||||
@@ -73,6 +76,9 @@ class ChatJoinRequest(TelegramObject):
|
||||
chat (:class:`telegram.Chat`): Chat to which the request was sent.
|
||||
from_user (:class:`telegram.User`): User that sent the join request.
|
||||
date (:class:`datetime.datetime`): Date the request was sent.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
user_chat_id (:obj:`int`): Identifier of a private chat with the user who sent the join
|
||||
request. This number may have more than 32 significant bits and some programming
|
||||
languages may have difficulty/silent defects in interpreting it. But it has at most 52
|
||||
@@ -124,9 +130,12 @@ class ChatJoinRequest(TelegramObject):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["chat"] = Chat.de_json(data.get("chat"), bot)
|
||||
data["from_user"] = User.de_json(data.pop("from", None), bot)
|
||||
data["date"] = from_timestamp(data.get("date", None))
|
||||
data["date"] = from_timestamp(data.get("date", None), tzinfo=loc_tzinfo)
|
||||
data["invite_link"] = ChatInviteLink.de_json(data.get("invite_link"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
+17
-2
@@ -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
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -125,7 +125,10 @@ class ChatMember(TelegramObject):
|
||||
|
||||
data["user"] = User.de_json(data.get("user"), bot)
|
||||
if "until_date" in data:
|
||||
data["until_date"] = from_timestamp(data["until_date"])
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["until_date"] = from_timestamp(data["until_date"], tzinfo=loc_tzinfo)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -386,6 +389,9 @@ class ChatMemberRestricted(ChatMember):
|
||||
.. versionadded:: 20.0
|
||||
until_date (:class:`datetime.datetime`): Date when restrictions
|
||||
will be lifted for this user.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
can_send_audios (:obj:`bool`): :obj:`True`, if the user is allowed to send audios.
|
||||
|
||||
.. versionadded:: 20.1
|
||||
@@ -438,6 +444,9 @@ class ChatMemberRestricted(ChatMember):
|
||||
.. versionadded:: 20.0
|
||||
until_date (:class:`datetime.datetime`): Date when restrictions
|
||||
will be lifted for this user.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
can_send_audios (:obj:`bool`): :obj:`True`, if the user is allowed to send audios.
|
||||
|
||||
.. versionadded:: 20.1
|
||||
@@ -565,6 +574,9 @@ class ChatMemberBanned(ChatMember):
|
||||
until_date (:class:`datetime.datetime`): Date when restrictions
|
||||
will be lifted for this user.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
|
||||
Attributes:
|
||||
status (:obj:`str`): The member's status in the chat,
|
||||
always :tg-const:`telegram.ChatMember.BANNED`.
|
||||
@@ -572,6 +584,9 @@ class ChatMemberBanned(ChatMember):
|
||||
until_date (:class:`datetime.datetime`): Date when restrictions
|
||||
will be lifted for this user.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("until_date",)
|
||||
|
||||
@@ -25,7 +25,7 @@ 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
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -52,20 +52,34 @@ class ChatMemberUpdated(TelegramObject):
|
||||
from_user (:class:`telegram.User`): Performer of the action, which resulted in the change.
|
||||
date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to
|
||||
:class:`datetime.datetime`.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
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. For joining by invite link events only.
|
||||
via_chat_folder_invite_link (:obj:`bool`, optional): :obj:`True`, if the user joined the
|
||||
chat via a chat folder invite link
|
||||
|
||||
.. versionadded:: 20.3
|
||||
|
||||
Attributes:
|
||||
chat (:class:`telegram.Chat`): Chat the user belongs to.
|
||||
from_user (:class:`telegram.User`): Performer of the action, which resulted in the change.
|
||||
date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to
|
||||
:class:`datetime.datetime`.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
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. For joining by invite link events only.
|
||||
via_chat_folder_invite_link (:obj:`bool`): Optional. :obj:`True`, if the user joined the
|
||||
chat via a chat folder invite link
|
||||
|
||||
.. versionadded:: 20.3
|
||||
|
||||
"""
|
||||
|
||||
@@ -76,6 +90,7 @@ class ChatMemberUpdated(TelegramObject):
|
||||
"old_chat_member",
|
||||
"new_chat_member",
|
||||
"invite_link",
|
||||
"via_chat_folder_invite_link",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@@ -86,6 +101,7 @@ class ChatMemberUpdated(TelegramObject):
|
||||
old_chat_member: ChatMember,
|
||||
new_chat_member: ChatMember,
|
||||
invite_link: ChatInviteLink = None,
|
||||
via_chat_folder_invite_link: bool = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -96,6 +112,7 @@ class ChatMemberUpdated(TelegramObject):
|
||||
self.date: datetime.datetime = date
|
||||
self.old_chat_member: ChatMember = old_chat_member
|
||||
self.new_chat_member: ChatMember = new_chat_member
|
||||
self.via_chat_folder_invite_link: Optional[bool] = via_chat_folder_invite_link
|
||||
|
||||
# Optionals
|
||||
self.invite_link: Optional[ChatInviteLink] = invite_link
|
||||
@@ -118,9 +135,12 @@ class ChatMemberUpdated(TelegramObject):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["chat"] = Chat.de_json(data.get("chat"), bot)
|
||||
data["from_user"] = User.de_json(data.pop("from", None), bot)
|
||||
data["date"] = from_timestamp(data.get("date"))
|
||||
data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
|
||||
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)
|
||||
|
||||
@@ -22,6 +22,10 @@ from typing import TYPE_CHECKING, Optional, Type, TypeVar
|
||||
from telegram._files._basemedium import _BaseMedium
|
||||
from telegram._files.photosize import PhotoSize
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings_transition import (
|
||||
warn_about_deprecated_arg_return_new_arg,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
@@ -46,18 +50,25 @@ class _BaseThumbedMedium(_BaseMedium):
|
||||
file_size (:obj:`int`, optional): File size.
|
||||
thumb (:class:`telegram.PhotoSize`, optional): Thumbnail as defined by sender.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail`.
|
||||
thumbnail (:class:`telegram.PhotoSize`, optional): Thumbnail as defined by sender.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
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.
|
||||
file_size (:obj:`int`): Optional. File size.
|
||||
thumb (:class:`telegram.PhotoSize`): Optional. Thumbnail as defined by sender.
|
||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Thumbnail as defined by sender.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("thumb",)
|
||||
__slots__ = ("thumbnail",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -65,6 +76,7 @@ class _BaseThumbedMedium(_BaseMedium):
|
||||
file_unique_id: str,
|
||||
file_size: int = None,
|
||||
thumb: PhotoSize = None,
|
||||
thumbnail: PhotoSize = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -74,7 +86,27 @@ class _BaseThumbedMedium(_BaseMedium):
|
||||
file_size=file_size,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
self.thumb: Optional[PhotoSize] = thumb
|
||||
|
||||
self.thumbnail: Optional[PhotoSize] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb,
|
||||
new_arg=thumbnail,
|
||||
deprecated_arg_name="thumb",
|
||||
new_arg_name="thumbnail",
|
||||
bot_api_version="6.6",
|
||||
stacklevel=3,
|
||||
)
|
||||
|
||||
@property
|
||||
def thumb(self) -> Optional[PhotoSize]:
|
||||
""":class:`telegram.PhotoSize`: Optional. Thumbnail as defined by sender.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb", new_attr_name="thumbnail", bot_api_version="6.6"
|
||||
)
|
||||
return self.thumbnail
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
@@ -87,7 +119,13 @@ class _BaseThumbedMedium(_BaseMedium):
|
||||
return None
|
||||
|
||||
# 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)
|
||||
if not isinstance(data.get("thumbnail"), PhotoSize):
|
||||
data["thumbnail"] = PhotoSize.de_json(data.get("thumbnail"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
api_kwargs = {}
|
||||
# This is a deprecated field that TG still returns for backwards compatibility
|
||||
# Let's filter it out to speed up the de-json process
|
||||
if data.get("thumb") is not None:
|
||||
api_kwargs["thumb"] = data.pop("thumb")
|
||||
|
||||
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
|
||||
|
||||
@@ -40,9 +40,16 @@ class Animation(_BaseThumbedMedium):
|
||||
height (:obj:`int`): Video height as defined by sender.
|
||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
||||
thumb (:class:`telegram.PhotoSize`, optional): Animation thumbnail as defined by sender.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail`.
|
||||
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.
|
||||
thumbnail (:class:`telegram.PhotoSize`, optional): Animation thumbnail as defined by
|
||||
sender.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
@@ -53,11 +60,13 @@ class Animation(_BaseThumbedMedium):
|
||||
width (:obj:`int`): Video width as defined by sender.
|
||||
height (:obj:`int`): Video height as defined by sender.
|
||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
||||
thumb (:class:`telegram.PhotoSize`): Optional. Animation thumbnail as defined by sender.
|
||||
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.
|
||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Animation thumbnail as defined by
|
||||
sender.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
"""
|
||||
|
||||
@@ -74,6 +83,7 @@ class Animation(_BaseThumbedMedium):
|
||||
file_name: str = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
thumbnail: PhotoSize = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -83,6 +93,7 @@ class Animation(_BaseThumbedMedium):
|
||||
file_size=file_size,
|
||||
thumb=thumb,
|
||||
api_kwargs=api_kwargs,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
with self._unfrozen():
|
||||
# Required
|
||||
|
||||
@@ -46,6 +46,13 @@ class Audio(_BaseThumbedMedium):
|
||||
thumb (:class:`telegram.PhotoSize`, optional): Thumbnail of the album cover to
|
||||
which the music file belongs.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail`.
|
||||
thumbnail (:class:`telegram.PhotoSize`, optional): Thumbnail of the album cover to
|
||||
which the music file belongs.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
@@ -58,9 +65,11 @@ class Audio(_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.
|
||||
thumb (:class:`telegram.PhotoSize`): Optional. Thumbnail of the album cover to
|
||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Thumbnail of the album cover to
|
||||
which the music file belongs.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
|
||||
"""
|
||||
|
||||
@@ -77,6 +86,7 @@ class Audio(_BaseThumbedMedium):
|
||||
file_size: int = None,
|
||||
thumb: PhotoSize = None,
|
||||
file_name: str = None,
|
||||
thumbnail: PhotoSize = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -85,6 +95,7 @@ class Audio(_BaseThumbedMedium):
|
||||
file_unique_id=file_unique_id,
|
||||
file_size=file_size,
|
||||
thumb=thumb,
|
||||
thumbnail=thumbnail,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
with self._unfrozen():
|
||||
|
||||
@@ -37,19 +37,27 @@ class Document(_BaseThumbedMedium):
|
||||
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.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail`.
|
||||
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.
|
||||
thumbnail (:class:`telegram.PhotoSize`, optional): Document thumbnail as defined by sender.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
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.
|
||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Document thumbnail as defined by sender.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
"""
|
||||
|
||||
@@ -63,6 +71,7 @@ class Document(_BaseThumbedMedium):
|
||||
file_name: str = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
thumbnail: PhotoSize = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -71,6 +80,7 @@ class Document(_BaseThumbedMedium):
|
||||
file_unique_id=file_unique_id,
|
||||
file_size=file_size,
|
||||
thumb=thumb,
|
||||
thumbnail=thumbnail,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
with self._unfrozen():
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram InputFile."""
|
||||
|
||||
import logging
|
||||
import mimetypes
|
||||
from typing import IO, Optional, Union
|
||||
from uuid import uuid4
|
||||
@@ -27,7 +26,6 @@ from telegram._utils.files import load_file
|
||||
from telegram._utils.types import FieldTuple
|
||||
|
||||
_DEFAULT_MIME_TYPE = "application/octet-stream"
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class InputFile:
|
||||
|
||||
+123
-12
@@ -31,6 +31,10 @@ 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
|
||||
from telegram._utils.warnings_transition import (
|
||||
warn_about_deprecated_attr_in_property,
|
||||
warn_about_thumb_return_thumbnail,
|
||||
)
|
||||
from telegram.constants import InputMediaType
|
||||
|
||||
MediaType = Union[Animation, Audio, Document, PhotoSize, Video]
|
||||
@@ -138,6 +142,9 @@ class InputMediaAnimation(InputMedia):
|
||||
|
||||
.. versionchanged:: 13.2
|
||||
Accept :obj:`bytes` as input.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail`.
|
||||
caption (:obj:`str`, optional): Caption of the animation to be sent,
|
||||
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
|
||||
after entities parsing.
|
||||
@@ -154,11 +161,14 @@ class InputMediaAnimation(InputMedia):
|
||||
with a spoiler animation.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
|
||||
optional): |thumbdocstringnopath|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.ANIMATION`.
|
||||
media (:obj:`str` | :class:`telegram.InputFile`): Animation to send.
|
||||
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.
|
||||
@@ -176,9 +186,12 @@ class InputMediaAnimation(InputMedia):
|
||||
spoiler animation.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
|
||||
__slots__ = ("duration", "height", "thumb", "width", "has_spoiler")
|
||||
__slots__ = ("duration", "height", "width", "has_spoiler", "thumbnail")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -192,6 +205,7 @@ class InputMediaAnimation(InputMedia):
|
||||
caption_entities: Sequence[MessageEntity] = None,
|
||||
filename: str = None,
|
||||
has_spoiler: bool = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -205,6 +219,7 @@ class InputMediaAnimation(InputMedia):
|
||||
# things to work in local mode.
|
||||
media = parse_file_input(media, filename=filename, attach=True, local_mode=True)
|
||||
|
||||
thumbnail = warn_about_thumb_return_thumbnail(deprecated_arg=thumb, new_arg=thumbnail)
|
||||
super().__init__(
|
||||
InputMediaType.ANIMATION,
|
||||
media,
|
||||
@@ -214,12 +229,26 @@ class InputMediaAnimation(InputMedia):
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
with self._unfrozen():
|
||||
self.thumb: Optional[Union[str, InputFile]] = self._parse_thumb_input(thumb)
|
||||
self.thumbnail: Optional[Union[str, InputFile]] = self._parse_thumb_input(thumbnail)
|
||||
self.width: Optional[int] = width
|
||||
self.height: Optional[int] = height
|
||||
self.duration: Optional[int] = duration
|
||||
self.has_spoiler: Optional[bool] = has_spoiler
|
||||
|
||||
@property
|
||||
def thumb(self) -> Optional[Union[str, InputFile]]:
|
||||
""":class:`telegram.InputFile`: Optional. |thumbdocstringbase|
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb",
|
||||
new_attr_name="thumbnail",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail
|
||||
|
||||
|
||||
class InputMediaPhoto(InputMedia):
|
||||
"""Represents a photo to be sent.
|
||||
@@ -343,10 +372,17 @@ class InputMediaVideo(InputMedia):
|
||||
|
||||
.. versionchanged:: 13.2
|
||||
Accept :obj:`bytes` as input.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail`.
|
||||
has_spoiler (:obj:`bool`, optional): Pass :obj:`True`, if the video needs to be covered
|
||||
with a spoiler animation.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
|
||||
optional): |thumbdocstringnopath|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.VIDEO`.
|
||||
@@ -366,14 +402,23 @@ class InputMediaVideo(InputMedia):
|
||||
duration (:obj:`int`): Optional. Video duration in seconds.
|
||||
supports_streaming (:obj:`bool`): Optional. :obj:`True`, if the uploaded video is
|
||||
suitable for streaming.
|
||||
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
|
||||
thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
|
||||
__slots__ = ("duration", "height", "thumb", "supports_streaming", "width", "has_spoiler")
|
||||
__slots__ = (
|
||||
"duration",
|
||||
"height",
|
||||
"supports_streaming",
|
||||
"width",
|
||||
"has_spoiler",
|
||||
"thumbnail",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -388,6 +433,7 @@ class InputMediaVideo(InputMedia):
|
||||
caption_entities: Sequence[MessageEntity] = None,
|
||||
filename: str = None,
|
||||
has_spoiler: bool = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -401,6 +447,7 @@ class InputMediaVideo(InputMedia):
|
||||
# things to work in local mode.
|
||||
media = parse_file_input(media, filename=filename, attach=True, local_mode=True)
|
||||
|
||||
thumbnail = warn_about_thumb_return_thumbnail(deprecated_arg=thumb, new_arg=thumbnail)
|
||||
super().__init__(
|
||||
InputMediaType.VIDEO,
|
||||
media,
|
||||
@@ -413,10 +460,24 @@ class InputMediaVideo(InputMedia):
|
||||
self.width: Optional[int] = width
|
||||
self.height: Optional[int] = height
|
||||
self.duration: Optional[int] = duration
|
||||
self.thumb: Optional[Union[str, InputFile]] = self._parse_thumb_input(thumb)
|
||||
self.thumbnail: Optional[Union[str, InputFile]] = self._parse_thumb_input(thumbnail)
|
||||
self.supports_streaming: Optional[bool] = supports_streaming
|
||||
self.has_spoiler: Optional[bool] = has_spoiler
|
||||
|
||||
@property
|
||||
def thumb(self) -> Optional[Union[str, InputFile]]:
|
||||
""":class:`telegram.InputFile`: Optional. |thumbdocstringbase|
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb",
|
||||
new_attr_name="thumbnail",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail
|
||||
|
||||
|
||||
class InputMediaAudio(InputMedia):
|
||||
"""Represents an audio file to be treated as music to be sent.
|
||||
@@ -459,6 +520,13 @@ class InputMediaAudio(InputMedia):
|
||||
.. versionchanged:: 13.2
|
||||
Accept :obj:`bytes` as input.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail`.
|
||||
thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
|
||||
optional): |thumbdocstringnopath|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.AUDIO`.
|
||||
media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send.
|
||||
@@ -476,11 +544,13 @@ class InputMediaAudio(InputMedia):
|
||||
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. |thumbdocstringbase|
|
||||
thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("duration", "performer", "thumb", "title")
|
||||
__slots__ = ("duration", "performer", "title", "thumbnail")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -493,6 +563,7 @@ class InputMediaAudio(InputMedia):
|
||||
title: str = None,
|
||||
caption_entities: Sequence[MessageEntity] = None,
|
||||
filename: str = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -506,6 +577,7 @@ class InputMediaAudio(InputMedia):
|
||||
# things to work in local mode.
|
||||
media = parse_file_input(media, filename=filename, attach=True, local_mode=True)
|
||||
|
||||
thumbnail = warn_about_thumb_return_thumbnail(deprecated_arg=thumb, new_arg=thumbnail)
|
||||
super().__init__(
|
||||
InputMediaType.AUDIO,
|
||||
media,
|
||||
@@ -515,11 +587,25 @@ class InputMediaAudio(InputMedia):
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
with self._unfrozen():
|
||||
self.thumb: Optional[Union[str, InputFile]] = self._parse_thumb_input(thumb)
|
||||
self.thumbnail: Optional[Union[str, InputFile]] = self._parse_thumb_input(thumbnail)
|
||||
self.duration: Optional[int] = duration
|
||||
self.title: Optional[str] = title
|
||||
self.performer: Optional[str] = performer
|
||||
|
||||
@property
|
||||
def thumb(self) -> Optional[Union[str, InputFile]]:
|
||||
""":class:`telegram.InputFile`: Optional. |thumbdocstringbase|
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb",
|
||||
new_attr_name="thumbnail",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail
|
||||
|
||||
|
||||
class InputMediaDocument(InputMedia):
|
||||
"""Represents a general file to be sent.
|
||||
@@ -552,9 +638,16 @@ class InputMediaDocument(InputMedia):
|
||||
|
||||
.. versionchanged:: 13.2
|
||||
Accept :obj:`bytes` as input.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail`.
|
||||
disable_content_type_detection (:obj:`bool`, optional): Disables automatic server-side
|
||||
content type detection for files uploaded using multipart/form-data. Always
|
||||
:obj:`True`, if the document is sent as part of an album.
|
||||
thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
|
||||
optional): |thumbdocstringnopath|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.DOCUMENT`.
|
||||
@@ -569,14 +662,15 @@ class InputMediaDocument(InputMedia):
|
||||
|
||||
* |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
|
||||
:obj:`True`, if the document is sent as part of an album.
|
||||
thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
|
||||
__slots__ = ("disable_content_type_detection", "thumb")
|
||||
__slots__ = ("disable_content_type_detection", "thumbnail")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -587,12 +681,15 @@ class InputMediaDocument(InputMedia):
|
||||
disable_content_type_detection: bool = None,
|
||||
caption_entities: Sequence[MessageEntity] = None,
|
||||
filename: str = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
# 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)
|
||||
|
||||
thumbnail = warn_about_thumb_return_thumbnail(deprecated_arg=thumb, new_arg=thumbnail)
|
||||
super().__init__(
|
||||
InputMediaType.DOCUMENT,
|
||||
media,
|
||||
@@ -602,5 +699,19 @@ class InputMediaDocument(InputMedia):
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
with self._unfrozen():
|
||||
self.thumb: Optional[Union[str, InputFile]] = self._parse_thumb_input(thumb)
|
||||
self.thumbnail: Optional[Union[str, InputFile]] = self._parse_thumb_input(thumbnail)
|
||||
self.disable_content_type_detection: Optional[bool] = disable_content_type_detection
|
||||
|
||||
@property
|
||||
def thumb(self) -> Optional[Union[str, InputFile]]:
|
||||
""":class:`telegram.InputFile`: Optional. |thumbdocstringbase|
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb",
|
||||
new_attr_name="thumbnail",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram InputSticker."""
|
||||
|
||||
from typing import Optional, Sequence, Tuple, Union
|
||||
|
||||
from telegram._files.inputfile import InputFile
|
||||
from telegram._files.sticker import MaskPosition
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.files import parse_file_input
|
||||
from telegram._utils.types import FileInput, JSONDict
|
||||
|
||||
|
||||
class InputSticker(TelegramObject):
|
||||
"""
|
||||
This object describes a sticker to be added to a sticker set.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Args:
|
||||
sticker (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path`): The
|
||||
added sticker. |uploadinputnopath| Animated and video stickers can't be uploaded via
|
||||
HTTP URL.
|
||||
emoji_list (Sequence[:obj:`str`]): Sequence of
|
||||
:tg-const:`telegram.constants.StickerLimit.MIN_STICKER_EMOJI` -
|
||||
:tg-const:`telegram.constants.StickerLimit.MAX_STICKER_EMOJI` emoji associated with the
|
||||
sticker.
|
||||
mask_position (:obj:`telegram.MaskPosition`, optional): Position where the mask should be
|
||||
placed on faces. For ":tg-const:`telegram.constants.StickerType.MASK`" stickers only.
|
||||
keywords (Sequence[:obj:`str`], optional): Sequence of
|
||||
0-:tg-const:`telegram.constants.StickerLimit.MAX_SEARCH_KEYWORDS` search keywords
|
||||
for the sticker with the total length of up to
|
||||
:tg-const:`telegram.constants.StickerLimit.MAX_KEYWORD_LENGTH` characters. For
|
||||
":tg-const:`telegram.constants.StickerType.REGULAR`" and
|
||||
":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only.
|
||||
|
||||
Attributes:
|
||||
sticker (:obj:`str` | :class:`telegram.InputFile`): The added sticker.
|
||||
emoji_list (Tuple[:obj:`str`]): Tuple of
|
||||
:tg-const:`telegram.constants.StickerLimit.MIN_STICKER_EMOJI` -
|
||||
:tg-const:`telegram.constants.StickerLimit.MAX_STICKER_EMOJI` emoji associated with the
|
||||
sticker.
|
||||
mask_position (:obj:`telegram.MaskPosition`): Optional. Position where the mask should be
|
||||
placed on faces. For ":tg-const:`telegram.constants.StickerType.MASK`" stickers only.
|
||||
keywords (Tuple[:obj:`str`]): Optional. Tuple of
|
||||
0-:tg-const:`telegram.constants.StickerLimit.MAX_SEARCH_KEYWORDS` search keywords
|
||||
for the sticker with the total length of up to
|
||||
:tg-const:`telegram.constants.StickerLimit.MAX_KEYWORD_LENGTH` characters. For
|
||||
":tg-const:`telegram.constants.StickerType.REGULAR`" and
|
||||
":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("sticker", "emoji_list", "mask_position", "keywords")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sticker: FileInput,
|
||||
emoji_list: Sequence[str],
|
||||
mask_position: MaskPosition = None,
|
||||
keywords: Sequence[str] = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
# We use local_mode=True because we don't have access to the actual setting and want
|
||||
# things to work in local mode.
|
||||
self.sticker: Union[str, InputFile] = parse_file_input(
|
||||
sticker,
|
||||
local_mode=True,
|
||||
attach=True,
|
||||
)
|
||||
self.emoji_list: Tuple[str, ...] = parse_sequence_arg(emoji_list)
|
||||
self.mask_position: Optional[MaskPosition] = mask_position
|
||||
self.keywords: Tuple[str, ...] = parse_sequence_arg(keywords)
|
||||
|
||||
self._freeze()
|
||||
+73
-12
@@ -26,6 +26,10 @@ 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
|
||||
from telegram._utils.warnings_transition import (
|
||||
warn_about_deprecated_attr_in_property,
|
||||
warn_about_thumb_return_thumbnail,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
@@ -61,6 +65,9 @@ class Sticker(_BaseThumbedMedium):
|
||||
.. versionadded:: 20.0
|
||||
thumb (:class:`telegram.PhotoSize`, optional): Sticker thumbnail in the ``.WEBP`` or
|
||||
``.JPG`` format.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail`.
|
||||
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
|
||||
@@ -75,6 +82,15 @@ class Sticker(_BaseThumbedMedium):
|
||||
custom emoji.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
thumbnail (:class:`telegram.PhotoSize`, optional): Sticker thumbnail in the ``.WEBP`` or
|
||||
``.JPG`` format.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
needs_repainting (:obj:`bool`, optional): :obj:`True`, if the sticker must be repainted to
|
||||
a text color in messages, the color of the Telegram Premium badge in emoji status,
|
||||
white color on chat photos, or another appropriate color in other places.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
@@ -93,8 +109,6 @@ class Sticker(_BaseThumbedMedium):
|
||||
format, which is determined by the fields :attr:`is_animated` and :attr:`is_video`.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
thumb (:class:`telegram.PhotoSize`): Optional. Sticker thumbnail in the ``.WEBP`` or
|
||||
``.JPG`` format.
|
||||
emoji (:obj:`str`): Optional. Emoji associated with the sticker.
|
||||
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
|
||||
@@ -109,6 +123,15 @@ class Sticker(_BaseThumbedMedium):
|
||||
custom emoji.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Sticker thumbnail in the ``.WEBP`` or
|
||||
``.JPG`` format.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
needs_repainting (:obj:`bool`): Optional. :obj:`True`, if the sticker must be repainted to
|
||||
a text color in messages, the color of the Telegram Premium badge in emoji status,
|
||||
white color on chat photos, or another appropriate color in other places.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
@@ -122,6 +145,7 @@ class Sticker(_BaseThumbedMedium):
|
||||
"premium_animation",
|
||||
"type",
|
||||
"custom_emoji_id",
|
||||
"needs_repainting",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@@ -140,6 +164,8 @@ class Sticker(_BaseThumbedMedium):
|
||||
mask_position: "MaskPosition" = None,
|
||||
premium_animation: "File" = None,
|
||||
custom_emoji_id: str = None,
|
||||
thumbnail: PhotoSize = None,
|
||||
needs_repainting: bool = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -148,6 +174,7 @@ class Sticker(_BaseThumbedMedium):
|
||||
file_unique_id=file_unique_id,
|
||||
file_size=file_size,
|
||||
thumb=thumb,
|
||||
thumbnail=thumbnail,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
with self._unfrozen():
|
||||
@@ -163,6 +190,7 @@ class Sticker(_BaseThumbedMedium):
|
||||
self.mask_position: Optional[MaskPosition] = mask_position
|
||||
self.premium_animation: Optional[File] = premium_animation
|
||||
self.custom_emoji_id: Optional[str] = custom_emoji_id
|
||||
self.needs_repainting: Optional[bool] = needs_repainting
|
||||
|
||||
REGULAR: ClassVar[str] = constants.StickerType.REGULAR
|
||||
""":const:`telegram.constants.StickerType.REGULAR`"""
|
||||
@@ -179,11 +207,17 @@ class Sticker(_BaseThumbedMedium):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["thumb"] = PhotoSize.de_json(data.get("thumb"), bot)
|
||||
data["thumbnail"] = PhotoSize.de_json(data.get("thumbnail"), bot)
|
||||
data["mask_position"] = MaskPosition.de_json(data.get("mask_position"), bot)
|
||||
data["premium_animation"] = File.de_json(data.get("premium_animation"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
api_kwargs = {}
|
||||
# This is a deprecated field that TG still returns for backwards compatibility
|
||||
# Let's filter it out to speed up the de-json process
|
||||
if data.get("thumb") is not None:
|
||||
api_kwargs["thumb"] = data.pop("thumb")
|
||||
|
||||
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
|
||||
|
||||
|
||||
class StickerSet(TelegramObject):
|
||||
@@ -220,6 +254,13 @@ class StickerSet(TelegramObject):
|
||||
thumb (:class:`telegram.PhotoSize`, optional): Sticker set thumbnail in the ``.WEBP``,
|
||||
``.TGS``, or ``.WEBM`` format.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail`.
|
||||
thumbnail (:class:`telegram.PhotoSize`, optional): Sticker set thumbnail in the ``.WEBP``,
|
||||
``.TGS``, or ``.WEBM`` format.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
name (:obj:`str`): Sticker set name.
|
||||
title (:obj:`str`): Sticker set title.
|
||||
@@ -237,9 +278,10 @@ class StickerSet(TelegramObject):
|
||||
:attr:`telegram.Sticker.CUSTOM_EMOJI`.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
thumb (:class:`telegram.PhotoSize`): Optional. Sticker set thumbnail in the ``.WEBP``,
|
||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Sticker set thumbnail in the ``.WEBP``,
|
||||
``.TGS``, or ``.WEBM`` format.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
@@ -247,7 +289,7 @@ class StickerSet(TelegramObject):
|
||||
"is_video",
|
||||
"name",
|
||||
"stickers",
|
||||
"thumb",
|
||||
"thumbnail",
|
||||
"title",
|
||||
"sticker_type",
|
||||
)
|
||||
@@ -261,6 +303,7 @@ class StickerSet(TelegramObject):
|
||||
is_video: bool,
|
||||
sticker_type: str,
|
||||
thumb: PhotoSize = None,
|
||||
thumbnail: PhotoSize = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -272,26 +315,44 @@ class StickerSet(TelegramObject):
|
||||
self.stickers: Tuple[Sticker, ...] = parse_sequence_arg(stickers)
|
||||
self.sticker_type: str = sticker_type
|
||||
# Optional
|
||||
self.thumb: Optional[PhotoSize] = thumb
|
||||
|
||||
self.thumbnail: Optional[PhotoSize] = warn_about_thumb_return_thumbnail(
|
||||
deprecated_arg=thumb, new_arg=thumbnail
|
||||
)
|
||||
self._id_attrs = (self.name,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@property
|
||||
def thumb(self) -> Optional[PhotoSize]:
|
||||
""":class:`telegram.PhotoSize`: Optional. Sticker set thumbnail in the ``.WEBP``,
|
||||
``.TGS``, or ``.WEBM`` format.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb",
|
||||
new_attr_name="thumbnail",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["StickerSet"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["thumb"] = PhotoSize.de_json(data.get("thumb"), bot)
|
||||
data["thumbnail"] = PhotoSize.de_json(data.get("thumbnail"), bot)
|
||||
data["stickers"] = Sticker.de_list(data.get("stickers"), bot)
|
||||
|
||||
api_kwargs = {}
|
||||
# This is a deprecated field that TG still returns for backwards compatibility
|
||||
# Let's filter it out to speed up the de-json process
|
||||
if "contains_masks" in data:
|
||||
api_kwargs["contains_masks"] = data.pop("contains_masks")
|
||||
# These are deprecated fields that TG still returns for backwards compatibility
|
||||
# Let's filter them out to speed up the de-json process
|
||||
for deprecated_field in ("contains_masks", "thumb"):
|
||||
if deprecated_field in data:
|
||||
api_kwargs[deprecated_field] = data.pop(deprecated_field)
|
||||
|
||||
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
|
||||
|
||||
|
||||
@@ -40,9 +40,15 @@ class Video(_BaseThumbedMedium):
|
||||
height (:obj:`int`): Video height as defined by sender.
|
||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
||||
thumb (:class:`telegram.PhotoSize`, optional): Video thumbnail.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail`.
|
||||
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.
|
||||
thumbnail (:class:`telegram.PhotoSize`, optional): Video thumbnail.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
@@ -53,11 +59,12 @@ class Video(_BaseThumbedMedium):
|
||||
width (:obj:`int`): Video width as defined by sender.
|
||||
height (:obj:`int`): Video height 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_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.
|
||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Video thumbnail.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
|
||||
__slots__ = ("duration", "file_name", "height", "mime_type", "width")
|
||||
@@ -73,6 +80,7 @@ class Video(_BaseThumbedMedium):
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
file_name: str = None,
|
||||
thumbnail: PhotoSize = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -81,6 +89,7 @@ class Video(_BaseThumbedMedium):
|
||||
file_unique_id=file_unique_id,
|
||||
file_size=file_size,
|
||||
thumb=thumb,
|
||||
thumbnail=thumbnail,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
with self._unfrozen():
|
||||
|
||||
@@ -39,7 +39,13 @@ class VideoNote(_BaseThumbedMedium):
|
||||
by sender.
|
||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
||||
thumb (:class:`telegram.PhotoSize`, optional): Video thumbnail.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail`.
|
||||
file_size (:obj:`int`, optional): File size in bytes.
|
||||
thumbnail (:class:`telegram.PhotoSize`, optional): Video thumbnail.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
@@ -50,8 +56,10 @@ class VideoNote(_BaseThumbedMedium):
|
||||
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.
|
||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Video thumbnail.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
"""
|
||||
|
||||
@@ -65,6 +73,7 @@ class VideoNote(_BaseThumbedMedium):
|
||||
duration: int,
|
||||
thumb: PhotoSize = None,
|
||||
file_size: int = None,
|
||||
thumbnail: PhotoSize = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -73,6 +82,7 @@ class VideoNote(_BaseThumbedMedium):
|
||||
file_unique_id=file_unique_id,
|
||||
file_size=file_size,
|
||||
thumb=thumb,
|
||||
thumbnail=thumbnail,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
with self._unfrozen():
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
# 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, Dict, List, Optional, Sequence, Tuple
|
||||
|
||||
from telegram._files.animation import Animation
|
||||
@@ -158,9 +157,6 @@ class Game(TelegramObject):
|
||||
if not self.text:
|
||||
raise RuntimeError("This Game has no 'text'.")
|
||||
|
||||
# Is it a narrow build, if so we don't need to convert
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
return self.text[entity.offset : entity.offset + entity.length]
|
||||
entity_text = self.text.encode("utf-16-le")
|
||||
entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2]
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ 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._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._webappinfo import WebAppInfo
|
||||
@@ -111,6 +112,10 @@ class InlineKeyboardButton(TelegramObject):
|
||||
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.
|
||||
|
||||
Tip:
|
||||
This is similar to the new parameter :paramref:`switch_inline_query_chosen_chat`,
|
||||
but gives no control over which chats can be selected.
|
||||
switch_inline_query_current_chat (:obj:`str`, optional): If set, pressing the button will
|
||||
insert the bot's username and the specified inline query in the current chat's input
|
||||
field. Can be empty, in which case only the bot's username will be inserted. This
|
||||
@@ -122,6 +127,20 @@ class InlineKeyboardButton(TelegramObject):
|
||||
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.
|
||||
switch_inline_query_chosen_chat (:obj:`telegram.SwitchInlineQueryChosenChat`, optional):
|
||||
If set, pressing the button will prompt the user to select one of their chats of the
|
||||
specified type, open that chat and insert the bot's username and the specified inline
|
||||
query in the input field.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
|
||||
Tip:
|
||||
This is similar to :paramref:`switch_inline_query`, but gives more control on
|
||||
which chats can be selected.
|
||||
|
||||
Caution:
|
||||
The PTB team has discovered that this field works correctly only if your Telegram
|
||||
client is released after April 20th 2023.
|
||||
|
||||
Attributes:
|
||||
text (:obj:`str`): Label text on the button.
|
||||
@@ -154,6 +173,10 @@ class InlineKeyboardButton(TelegramObject):
|
||||
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.
|
||||
|
||||
Tip:
|
||||
This is similar to the new parameter :paramref:`switch_inline_query_chosen_chat`,
|
||||
but gives no control over which chats can be selected.
|
||||
switch_inline_query_current_chat (:obj:`str`): Optional. If set, pressing the button will
|
||||
insert the bot's username and the specified inline query in the current chat's input
|
||||
field. Can be empty, in which case only the bot's username will be inserted. This
|
||||
@@ -165,7 +188,20 @@ class InlineKeyboardButton(TelegramObject):
|
||||
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.
|
||||
switch_inline_query_chosen_chat (:obj:`telegram.SwitchInlineQueryChosenChat`): Optional.
|
||||
If set, pressing the button will prompt the user to select one of their chats of the
|
||||
specified type, open that chat and insert the bot's username and the specified inline
|
||||
query in the input field.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
|
||||
Tip:
|
||||
This is similar to :attr:`switch_inline_query`, but gives more control on
|
||||
which chats can be selected.
|
||||
|
||||
Caution:
|
||||
The PTB team has discovered that this field works correctly only if your Telegram
|
||||
client is released after April 20th 2023.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
@@ -178,6 +214,7 @@ class InlineKeyboardButton(TelegramObject):
|
||||
"text",
|
||||
"login_url",
|
||||
"web_app",
|
||||
"switch_inline_query_chosen_chat",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@@ -191,6 +228,7 @@ class InlineKeyboardButton(TelegramObject):
|
||||
pay: bool = None,
|
||||
login_url: LoginUrl = None,
|
||||
web_app: WebAppInfo = None,
|
||||
switch_inline_query_chosen_chat: SwitchInlineQueryChosenChat = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -207,6 +245,9 @@ class InlineKeyboardButton(TelegramObject):
|
||||
self.callback_game: Optional[CallbackGame] = callback_game
|
||||
self.pay: Optional[bool] = pay
|
||||
self.web_app: Optional[WebAppInfo] = web_app
|
||||
self.switch_inline_query_chosen_chat: Optional[
|
||||
SwitchInlineQueryChosenChat
|
||||
] = switch_inline_query_chosen_chat
|
||||
self._id_attrs = ()
|
||||
self._set_id_attrs()
|
||||
|
||||
@@ -236,6 +277,9 @@ class InlineKeyboardButton(TelegramObject):
|
||||
data["login_url"] = LoginUrl.de_json(data.get("login_url"), bot)
|
||||
data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot)
|
||||
data["callback_game"] = CallbackGame.de_json(data.get("callback_game"), bot)
|
||||
data["switch_inline_query_chosen_chat"] = SwitchInlineQueryChosenChat.de_json(
|
||||
data.get("switch_inline_query_chosen_chat"), bot
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ from typing import TYPE_CHECKING, Callable, ClassVar, Optional, Sequence, Union
|
||||
|
||||
from telegram import constants
|
||||
from telegram._files.location import Location
|
||||
from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
@@ -146,6 +147,7 @@ class InlineQuery(TelegramObject):
|
||||
next_offset: str = None,
|
||||
switch_pm_text: str = None,
|
||||
switch_pm_parameter: str = None,
|
||||
button: InlineQueryResultsButton = None,
|
||||
*,
|
||||
current_offset: str = None,
|
||||
auto_pagination: bool = False,
|
||||
@@ -192,6 +194,7 @@ class InlineQuery(TelegramObject):
|
||||
next_offset=next_offset,
|
||||
switch_pm_text=switch_pm_text,
|
||||
switch_pm_parameter=switch_pm_parameter,
|
||||
button=button,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
|
||||
@@ -23,6 +23,10 @@ from typing import TYPE_CHECKING, Optional
|
||||
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
from telegram._inline.inlinequeryresult import InlineQueryResult
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings_transition import (
|
||||
warn_about_deprecated_arg_return_new_arg,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
from telegram.constants import InlineQueryResultType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -49,9 +53,27 @@ class InlineQueryResultArticle(InlineQueryResult):
|
||||
in the message.
|
||||
description (:obj:`str`, optional): Short description of the result.
|
||||
thumb_url (:obj:`str`, optional): Url of the thumbnail for the result.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_url`.
|
||||
thumb_width (:obj:`int`, optional): Thumbnail width.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_width`.
|
||||
thumb_height (:obj:`int`, optional): Thumbnail height.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_height`.
|
||||
thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_width (:obj:`int`, optional): Thumbnail width.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_height (:obj:`int`, optional): Thumbnail height.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.ARTICLE`.
|
||||
id (:obj:`str`): Unique identifier for this result,
|
||||
@@ -66,22 +88,28 @@ class InlineQueryResultArticle(InlineQueryResult):
|
||||
hide_url (:obj:`bool`): Optional. Pass :obj:`True`, if you don't want the URL to be shown
|
||||
in the message.
|
||||
description (:obj:`str`): Optional. Short description of the result.
|
||||
thumb_url (:obj:`str`): Optional. Url of the thumbnail for the result.
|
||||
thumb_width (:obj:`int`): Optional. Thumbnail width.
|
||||
thumb_height (:obj:`int`): Optional. Thumbnail height.
|
||||
thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_width (:obj:`int`): Optional. Thumbnail width.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_height (:obj:`int`): Optional. Thumbnail height.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"reply_markup",
|
||||
"thumb_width",
|
||||
"thumb_height",
|
||||
"hide_url",
|
||||
"url",
|
||||
"title",
|
||||
"description",
|
||||
"input_message_content",
|
||||
"thumb_url",
|
||||
"thumbnail_width",
|
||||
"thumbnail_height",
|
||||
"thumbnail_url",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@@ -96,6 +124,9 @@ class InlineQueryResultArticle(InlineQueryResult):
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
thumbnail_url: str = None,
|
||||
thumbnail_width: int = None,
|
||||
thumbnail_height: int = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -110,6 +141,66 @@ class InlineQueryResultArticle(InlineQueryResult):
|
||||
self.url: Optional[str] = url
|
||||
self.hide_url: Optional[bool] = hide_url
|
||||
self.description: Optional[str] = description
|
||||
self.thumb_url: Optional[str] = thumb_url
|
||||
self.thumb_width: Optional[int] = thumb_width
|
||||
self.thumb_height: Optional[int] = thumb_height
|
||||
self.thumbnail_url: Optional[str] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_url,
|
||||
new_arg=thumbnail_url,
|
||||
deprecated_arg_name="thumb_url",
|
||||
new_arg_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
self.thumbnail_width: Optional[int] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_width,
|
||||
new_arg=thumbnail_width,
|
||||
deprecated_arg_name="thumb_width",
|
||||
new_arg_name="thumbnail_width",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
self.thumbnail_height: Optional[int] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_height,
|
||||
new_arg=thumbnail_height,
|
||||
deprecated_arg_name="thumb_height",
|
||||
new_arg_name="thumbnail_height",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
|
||||
@property
|
||||
def thumb_url(self) -> Optional[str]:
|
||||
""":obj:`str`: Optional. Url of the thumbnail for the result.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_url`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_url",
|
||||
new_attr_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_url
|
||||
|
||||
@property
|
||||
def thumb_width(self) -> Optional[int]:
|
||||
""":obj:`str`: Optional. Thumbnail width.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_width`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_width",
|
||||
new_attr_name="thumbnail_width",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_width
|
||||
|
||||
@property
|
||||
def thumb_height(self) -> Optional[int]:
|
||||
""":obj:`str`: Optional. Thumbnail height.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_height`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_height",
|
||||
new_attr_name="thumbnail_height",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_height
|
||||
|
||||
@@ -23,6 +23,10 @@ from typing import TYPE_CHECKING, Optional
|
||||
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
from telegram._inline.inlinequeryresult import InlineQueryResult
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings_transition import (
|
||||
warn_about_deprecated_arg_return_new_arg,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
from telegram.constants import InlineQueryResultType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -49,9 +53,27 @@ class InlineQueryResultContact(InlineQueryResult):
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the contact.
|
||||
thumb_url (:obj:`str`, optional): Url of the thumbnail for the result.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_url`.
|
||||
thumb_width (:obj:`int`, optional): Thumbnail width.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_width`.
|
||||
thumb_height (:obj:`int`, optional): Thumbnail height.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_height`.
|
||||
thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_width (:obj:`int`, optional): Thumbnail width.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_height (:obj:`int`, optional): Thumbnail height.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.CONTACT`.
|
||||
id (:obj:`str`): Unique identifier for this result,
|
||||
@@ -66,22 +88,28 @@ class InlineQueryResultContact(InlineQueryResult):
|
||||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
||||
message to be sent instead of the contact.
|
||||
thumb_url (:obj:`str`): Optional. Url of the thumbnail for the result.
|
||||
thumb_width (:obj:`int`): Optional. Thumbnail width.
|
||||
thumb_height (:obj:`int`): Optional. Thumbnail height.
|
||||
thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_width (:obj:`int`): Optional. Thumbnail width.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_height (:obj:`int`): Optional. Thumbnail height.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"reply_markup",
|
||||
"thumb_width",
|
||||
"thumb_height",
|
||||
"thumbnail_width",
|
||||
"thumbnail_height",
|
||||
"vcard",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"phone_number",
|
||||
"input_message_content",
|
||||
"thumb_url",
|
||||
"thumbnail_url",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@@ -96,6 +124,9 @@ class InlineQueryResultContact(InlineQueryResult):
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
vcard: str = None,
|
||||
thumbnail_url: str = None,
|
||||
thumbnail_width: int = None,
|
||||
thumbnail_height: int = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -110,6 +141,66 @@ class InlineQueryResultContact(InlineQueryResult):
|
||||
self.vcard: Optional[str] = vcard
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.thumb_url: Optional[str] = thumb_url
|
||||
self.thumb_width: Optional[int] = thumb_width
|
||||
self.thumb_height: Optional[int] = thumb_height
|
||||
self.thumbnail_url: Optional[str] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_url,
|
||||
new_arg=thumbnail_url,
|
||||
deprecated_arg_name="thumb_url",
|
||||
new_arg_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
self.thumbnail_width: Optional[int] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_width,
|
||||
new_arg=thumbnail_width,
|
||||
deprecated_arg_name="thumb_width",
|
||||
new_arg_name="thumbnail_width",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
self.thumbnail_height: Optional[int] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_height,
|
||||
new_arg=thumbnail_height,
|
||||
deprecated_arg_name="thumb_height",
|
||||
new_arg_name="thumbnail_height",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
|
||||
@property
|
||||
def thumb_url(self) -> Optional[str]:
|
||||
""":obj:`str`: Optional. Url of the thumbnail for the result.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_url`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_url",
|
||||
new_attr_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_url
|
||||
|
||||
@property
|
||||
def thumb_width(self) -> Optional[int]:
|
||||
""":obj:`str`: Optional. Thumbnail width.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_width`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_width",
|
||||
new_attr_name="thumbnail_width",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_width
|
||||
|
||||
@property
|
||||
def thumb_height(self) -> Optional[int]:
|
||||
""":obj:`str`: Optional. Thumbnail height.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_height`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_height",
|
||||
new_attr_name="thumbnail_height",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_height
|
||||
|
||||
@@ -25,6 +25,10 @@ from telegram._messageentity import MessageEntity
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import JSONDict, ODVInput
|
||||
from telegram._utils.warnings_transition import (
|
||||
warn_about_deprecated_arg_return_new_arg,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
from telegram.constants import InlineQueryResultType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -63,9 +67,28 @@ class InlineQueryResultDocument(InlineQueryResult):
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the file.
|
||||
thumb_url (:obj:`str`, optional): URL of the thumbnail (JPEG only) for the file.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_url`.
|
||||
thumb_width (:obj:`int`, optional): Thumbnail width.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_width`.
|
||||
thumb_height (:obj:`int`, optional): Thumbnail height.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_height`.
|
||||
thumbnail_url (:obj:`str`, optional): URL of the thumbnail (JPEG only) for the file.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_width (:obj:`int`, optional): Thumbnail width.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_height (:obj:`int`, optional): Thumbnail height.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.DOCUMENT`.
|
||||
id (:obj:`str`): Unique identifier for this result,
|
||||
@@ -90,9 +113,15 @@ class InlineQueryResultDocument(InlineQueryResult):
|
||||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
||||
message to be sent instead of the file.
|
||||
thumb_url (:obj:`str`): Optional. URL of the thumbnail (JPEG only) for the file.
|
||||
thumb_width (:obj:`int`): Optional. Thumbnail width.
|
||||
thumb_height (:obj:`int`): Optional. Thumbnail height.
|
||||
thumbnail_url (:obj:`str`): Optional. URL of the thumbnail (JPEG only) for the file.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_width (:obj:`int`): Optional. Thumbnail width.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_height (:obj:`int`): Optional. Thumbnail height.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
"""
|
||||
|
||||
@@ -100,14 +129,14 @@ class InlineQueryResultDocument(InlineQueryResult):
|
||||
"reply_markup",
|
||||
"caption_entities",
|
||||
"document_url",
|
||||
"thumb_width",
|
||||
"thumb_height",
|
||||
"thumbnail_width",
|
||||
"thumbnail_height",
|
||||
"caption",
|
||||
"title",
|
||||
"description",
|
||||
"parse_mode",
|
||||
"mime_type",
|
||||
"thumb_url",
|
||||
"thumbnail_url",
|
||||
"input_message_content",
|
||||
)
|
||||
|
||||
@@ -126,6 +155,9 @@ class InlineQueryResultDocument(InlineQueryResult):
|
||||
thumb_height: int = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Sequence[MessageEntity] = None,
|
||||
thumbnail_url: str = None,
|
||||
thumbnail_width: int = None,
|
||||
thumbnail_height: int = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -143,6 +175,66 @@ class InlineQueryResultDocument(InlineQueryResult):
|
||||
self.description: Optional[str] = description
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.thumb_url: Optional[str] = thumb_url
|
||||
self.thumb_width: Optional[int] = thumb_width
|
||||
self.thumb_height: Optional[int] = thumb_height
|
||||
self.thumbnail_url: Optional[str] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_url,
|
||||
new_arg=thumbnail_url,
|
||||
deprecated_arg_name="thumb_url",
|
||||
new_arg_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
self.thumbnail_width: Optional[int] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_width,
|
||||
new_arg=thumbnail_width,
|
||||
deprecated_arg_name="thumb_width",
|
||||
new_arg_name="thumbnail_width",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
self.thumbnail_height: Optional[int] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_height,
|
||||
new_arg=thumbnail_height,
|
||||
deprecated_arg_name="thumb_height",
|
||||
new_arg_name="thumbnail_height",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
|
||||
@property
|
||||
def thumb_url(self) -> Optional[str]:
|
||||
""":obj:`str`: Optional. URL of the thumbnail (JPEG only) for the file.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_url`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_url",
|
||||
new_attr_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_url
|
||||
|
||||
@property
|
||||
def thumb_width(self) -> Optional[int]:
|
||||
""":obj:`str`: Optional. Thumbnail width.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_width`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_width",
|
||||
new_attr_name="thumbnail_width",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_width
|
||||
|
||||
@property
|
||||
def thumb_height(self) -> Optional[int]:
|
||||
""":obj:`str`: Optional. Thumbnail height.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_height`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_height",
|
||||
new_attr_name="thumbnail_height",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_height
|
||||
|
||||
@@ -25,6 +25,10 @@ from telegram._messageentity import MessageEntity
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import JSONDict, ODVInput
|
||||
from telegram._utils.warnings_transition import (
|
||||
warn_about_deprecated_arg_return_new_arg,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
from telegram.constants import InlineQueryResultType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -47,10 +51,20 @@ class InlineQueryResultGif(InlineQueryResult):
|
||||
gif_width (:obj:`int`, optional): Width of the GIF.
|
||||
gif_height (:obj:`int`, optional): Height of the GIF.
|
||||
gif_duration (:obj:`int`, optional): Duration of the GIF in seconds.
|
||||
thumb_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for
|
||||
the result.
|
||||
thumb_mime_type (:obj:`str`, optional): MIME type of the thumbnail, must be one of
|
||||
thumbnail_url (:obj:`str`, optional): URL of the static (JPEG or GIF) or animated (MPEG4)
|
||||
thumbnail for the result.
|
||||
|
||||
Warning:
|
||||
The Bot API does **not** define this as an optional argument. It is formally
|
||||
optional for backwards compatibility with the deprecated :paramref:`thumb_url`.
|
||||
If you pass neither :paramref:`thumbnail_url` nor :paramref:`thumb_url`,
|
||||
:class:`ValueError` will be raised.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_mime_type (:obj:`str`, optional): MIME type of the thumbnail, must be one of
|
||||
``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
title (:obj:`str`, optional): Title for the result.
|
||||
caption (:obj:`str`, optional): Caption of the GIF file to be sent,
|
||||
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
|
||||
@@ -65,6 +79,20 @@ class InlineQueryResultGif(InlineQueryResult):
|
||||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the GIF animation.
|
||||
thumb_mime_type (:obj:`str`, optional): MIME type of the thumbnail, must be one of
|
||||
``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_mime_type`.
|
||||
thumb_url (:obj:`str`, optional): URL of the static (JPEG or GIF) or animated (MPEG4)
|
||||
thumbnail for the result.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_url`.
|
||||
|
||||
Raises:
|
||||
:class:`ValueError`: If neither :paramref:`thumbnail_url` nor :paramref:`thumb_url` is
|
||||
supplied or if both are supplied and are not equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.GIF`.
|
||||
@@ -75,10 +103,14 @@ class InlineQueryResultGif(InlineQueryResult):
|
||||
gif_width (:obj:`int`): Optional. Width of the GIF.
|
||||
gif_height (:obj:`int`): Optional. Height of the GIF.
|
||||
gif_duration (:obj:`int`): Optional. Duration of the GIF in seconds.
|
||||
thumb_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for
|
||||
the result.
|
||||
thumb_mime_type (:obj:`str`): Optional. MIME type of the thumbnail, must be one of
|
||||
thumbnail_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail
|
||||
for the result.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_mime_type (:obj:`str`): Optional. MIME type of the thumbnail, must be one of
|
||||
``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
title (:obj:`str`): Optional. Title for the result.
|
||||
caption (:obj:`str`): Optional. Caption of the GIF file to be sent,
|
||||
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
|
||||
@@ -100,7 +132,7 @@ class InlineQueryResultGif(InlineQueryResult):
|
||||
__slots__ = (
|
||||
"reply_markup",
|
||||
"gif_height",
|
||||
"thumb_mime_type",
|
||||
"thumbnail_mime_type",
|
||||
"caption_entities",
|
||||
"gif_width",
|
||||
"title",
|
||||
@@ -109,14 +141,17 @@ class InlineQueryResultGif(InlineQueryResult):
|
||||
"gif_duration",
|
||||
"input_message_content",
|
||||
"gif_url",
|
||||
"thumb_url",
|
||||
"thumbnail_url",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id: str, # pylint: disable=redefined-builtin
|
||||
gif_url: str,
|
||||
thumb_url: str,
|
||||
# thumbnail_url is not optional in Telegram API, but we want to support thumb_url as well,
|
||||
# so thumbnail_url may not be passed. We will raise ValueError manually if neither
|
||||
# thumbnail_url nor thumb_url are passed
|
||||
thumbnail_url: str = None,
|
||||
gif_width: int = None,
|
||||
gif_height: int = None,
|
||||
title: str = None,
|
||||
@@ -127,14 +162,29 @@ class InlineQueryResultGif(InlineQueryResult):
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
thumb_mime_type: str = None,
|
||||
caption_entities: Sequence[MessageEntity] = None,
|
||||
thumbnail_mime_type: str = None,
|
||||
# thumb_url is not optional in Telegram API, but it is here, along with thumbnail_url.
|
||||
thumb_url: str = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
if not (thumbnail_url or thumb_url):
|
||||
raise ValueError(
|
||||
"You must pass either 'thumbnail_url' or 'thumb_url'. Note that 'thumb_url' is "
|
||||
"deprecated."
|
||||
)
|
||||
|
||||
# Required
|
||||
super().__init__(InlineQueryResultType.GIF, id, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.gif_url: str = gif_url
|
||||
self.thumb_url: str = thumb_url
|
||||
self.thumbnail_url: str = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_url,
|
||||
new_arg=thumbnail_url,
|
||||
deprecated_arg_name="thumb_url",
|
||||
new_arg_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
|
||||
# Optionals
|
||||
self.gif_width: Optional[int] = gif_width
|
||||
@@ -146,4 +196,40 @@ class InlineQueryResultGif(InlineQueryResult):
|
||||
self.caption_entities: Tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.thumb_mime_type: Optional[str] = thumb_mime_type
|
||||
self.thumbnail_mime_type: Optional[str] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_mime_type,
|
||||
new_arg=thumbnail_mime_type,
|
||||
deprecated_arg_name="thumb_mime_type",
|
||||
new_arg_name="thumbnail_mime_type",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
|
||||
@property
|
||||
def thumb_url(self) -> str:
|
||||
""":obj:`str`: URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the
|
||||
result.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_url`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_url",
|
||||
new_attr_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_url
|
||||
|
||||
@property
|
||||
def thumb_mime_type(self) -> Optional[str]:
|
||||
""":obj:`str`: Optional. Optional. MIME type of the thumbnail, must be one of
|
||||
``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_mime_type`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_mime_type",
|
||||
new_attr_name="thumbnail_mime_type",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_mime_type
|
||||
|
||||
@@ -24,6 +24,10 @@ from telegram import constants
|
||||
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
from telegram._inline.inlinequeryresult import InlineQueryResult
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings_transition import (
|
||||
warn_about_deprecated_arg_return_new_arg,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent
|
||||
@@ -63,9 +67,27 @@ class InlineQueryResultLocation(InlineQueryResult):
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the location.
|
||||
thumb_url (:obj:`str`, optional): Url of the thumbnail for the result.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_url`.
|
||||
thumb_width (:obj:`int`, optional): Thumbnail width.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_width`.
|
||||
thumb_height (:obj:`int`, optional): Thumbnail height.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_height`.
|
||||
thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_width (:obj:`int`, optional): Thumbnail width.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_height (:obj:`int`, optional): Thumbnail height.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.LOCATION`.
|
||||
id (:obj:`str`): Unique identifier for this result,
|
||||
@@ -94,17 +116,23 @@ class InlineQueryResultLocation(InlineQueryResult):
|
||||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
||||
message to be sent instead of the location.
|
||||
thumb_url (:obj:`str`): Optional. Url of the thumbnail for the result.
|
||||
thumb_width (:obj:`int`): Optional. Thumbnail width.
|
||||
thumb_height (:obj:`int`): Optional. Thumbnail height.
|
||||
thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_width (:obj:`int`): Optional. Thumbnail width.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_height (:obj:`int`): Optional. Thumbnail height.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"longitude",
|
||||
"reply_markup",
|
||||
"thumb_width",
|
||||
"thumb_height",
|
||||
"thumbnail_width",
|
||||
"thumbnail_height",
|
||||
"heading",
|
||||
"title",
|
||||
"live_period",
|
||||
@@ -112,7 +140,7 @@ class InlineQueryResultLocation(InlineQueryResult):
|
||||
"input_message_content",
|
||||
"latitude",
|
||||
"horizontal_accuracy",
|
||||
"thumb_url",
|
||||
"thumbnail_url",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@@ -130,6 +158,9 @@ class InlineQueryResultLocation(InlineQueryResult):
|
||||
horizontal_accuracy: float = None,
|
||||
heading: int = None,
|
||||
proximity_alert_radius: int = None,
|
||||
thumbnail_url: str = None,
|
||||
thumbnail_width: int = None,
|
||||
thumbnail_height: int = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -144,15 +175,75 @@ class InlineQueryResultLocation(InlineQueryResult):
|
||||
self.live_period: Optional[int] = live_period
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.thumb_url: Optional[str] = thumb_url
|
||||
self.thumb_width: Optional[int] = thumb_width
|
||||
self.thumb_height: Optional[int] = thumb_height
|
||||
self.thumbnail_url: Optional[str] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_url,
|
||||
new_arg=thumbnail_url,
|
||||
deprecated_arg_name="thumb_url",
|
||||
new_arg_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
self.thumbnail_width: Optional[int] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_width,
|
||||
new_arg=thumbnail_width,
|
||||
deprecated_arg_name="thumb_width",
|
||||
new_arg_name="thumbnail_width",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
self.thumbnail_height: Optional[int] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_height,
|
||||
new_arg=thumbnail_height,
|
||||
deprecated_arg_name="thumb_height",
|
||||
new_arg_name="thumbnail_height",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
self.horizontal_accuracy: Optional[float] = horizontal_accuracy
|
||||
self.heading: Optional[int] = heading
|
||||
self.proximity_alert_radius: Optional[int] = (
|
||||
int(proximity_alert_radius) if proximity_alert_radius else None
|
||||
)
|
||||
|
||||
@property
|
||||
def thumb_url(self) -> Optional[str]:
|
||||
""":obj:`str`: Optional. Url of the thumbnail for the result.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_url`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_url",
|
||||
new_attr_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_url
|
||||
|
||||
@property
|
||||
def thumb_width(self) -> Optional[int]:
|
||||
""":obj:`str`: Optional. Thumbnail width.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_width`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_width",
|
||||
new_attr_name="thumbnail_width",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_width
|
||||
|
||||
@property
|
||||
def thumb_height(self) -> Optional[int]:
|
||||
""":obj:`str`: Optional. Thumbnail height.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_height`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_height",
|
||||
new_attr_name="thumbnail_height",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_height
|
||||
|
||||
HORIZONTAL_ACCURACY: ClassVar[int] = constants.LocationLimit.HORIZONTAL_ACCURACY
|
||||
""":const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ from telegram._messageentity import MessageEntity
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import JSONDict, ODVInput
|
||||
from telegram._utils.warnings_transition import (
|
||||
warn_about_deprecated_arg_return_new_arg,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
from telegram.constants import InlineQueryResultType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -48,10 +52,20 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
||||
mpeg4_width (:obj:`int`, optional): Video width.
|
||||
mpeg4_height (:obj:`int`, optional): Video height.
|
||||
mpeg4_duration (:obj:`int`, optional): Video duration in seconds.
|
||||
thumb_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for
|
||||
the result.
|
||||
thumb_mime_type (:obj:`str`): Optional. MIME type of the thumbnail, must be one of
|
||||
thumbnail_url (:obj:`str`, optional): URL of the static (JPEG or GIF) or animated (MPEG4)
|
||||
thumbnail for the result.
|
||||
|
||||
Warning:
|
||||
The Bot API does **not** define this as an optional argument. It is formally
|
||||
optional for backwards compatibility with the deprecated :paramref:`thumb_url`.
|
||||
If you pass neither :paramref:`thumbnail_url` nor :paramref:`thumb_url`,
|
||||
:class:`ValueError` will be raised.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_mime_type (:obj:`str`, optional): MIME type of the thumbnail, must be one of
|
||||
``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
title (:obj:`str`, optional): Title for the result.
|
||||
caption (:obj:`str`, optional): Caption of the MPEG-4 file to be sent,
|
||||
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
|
||||
@@ -68,6 +82,10 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the video animation.
|
||||
|
||||
Raises:
|
||||
:class:`ValueError`: If neither :paramref:`thumbnail_url` nor :paramref:`thumb_url` is
|
||||
supplied or if both are supplied and are not equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.MPEG4GIF`.
|
||||
id (:obj:`str`): Unique identifier for this result,
|
||||
@@ -77,10 +95,14 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
||||
mpeg4_width (:obj:`int`): Optional. Video width.
|
||||
mpeg4_height (:obj:`int`): Optional. Video height.
|
||||
mpeg4_duration (:obj:`int`): Optional. Video duration in seconds.
|
||||
thumb_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for
|
||||
the result.
|
||||
thumb_mime_type (:obj:`str`): Optional. MIME type of the thumbnail, must be one of
|
||||
thumbnail_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail
|
||||
for the result.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_mime_type (:obj:`str`): Optional. MIME type of the thumbnail, must be one of
|
||||
``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
title (:obj:`str`): Optional. Title for the result.
|
||||
caption (:obj:`str`): Optional. Caption of the MPEG-4 file to be sent,
|
||||
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
|
||||
@@ -102,7 +124,7 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
||||
|
||||
__slots__ = (
|
||||
"reply_markup",
|
||||
"thumb_mime_type",
|
||||
"thumbnail_mime_type",
|
||||
"caption_entities",
|
||||
"mpeg4_duration",
|
||||
"mpeg4_width",
|
||||
@@ -112,14 +134,17 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
||||
"input_message_content",
|
||||
"mpeg4_url",
|
||||
"mpeg4_height",
|
||||
"thumb_url",
|
||||
"thumbnail_url",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id: str, # pylint: disable=redefined-builtin
|
||||
mpeg4_url: str,
|
||||
thumb_url: str,
|
||||
# thumbnail_url is not optional in Telegram API, but we want to support thumb_url as well,
|
||||
# so thumbnail_url may not be passed. We will raise ValueError manually if neither
|
||||
# thumbnail_url nor thumb_url are passed
|
||||
thumbnail_url: str = None,
|
||||
mpeg4_width: int = None,
|
||||
mpeg4_height: int = None,
|
||||
title: str = None,
|
||||
@@ -130,14 +155,29 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
thumb_mime_type: str = None,
|
||||
caption_entities: Sequence[MessageEntity] = None,
|
||||
thumbnail_mime_type: str = None,
|
||||
# thumb_url is not optional in Telegram API, but it is here, along with thumbnail_url.
|
||||
thumb_url: str = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
if not (thumbnail_url or thumb_url):
|
||||
raise ValueError(
|
||||
"You must pass either 'thumbnail_url' or 'thumb_url'. Note that 'thumb_url' is "
|
||||
"deprecated."
|
||||
)
|
||||
|
||||
# Required
|
||||
super().__init__(InlineQueryResultType.MPEG4GIF, id, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.mpeg4_url: str = mpeg4_url
|
||||
self.thumb_url: str = thumb_url
|
||||
self.thumbnail_url: str = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_url,
|
||||
new_arg=thumbnail_url,
|
||||
deprecated_arg_name="thumb_url",
|
||||
new_arg_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
|
||||
# Optional
|
||||
self.mpeg4_width: Optional[int] = mpeg4_width
|
||||
@@ -149,4 +189,40 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
||||
self.caption_entities: Tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.thumb_mime_type: Optional[str] = thumb_mime_type
|
||||
self.thumbnail_mime_type: Optional[str] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_mime_type,
|
||||
new_arg=thumbnail_mime_type,
|
||||
deprecated_arg_name="thumb_mime_type",
|
||||
new_arg_name="thumbnail_mime_type",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
|
||||
@property
|
||||
def thumb_url(self) -> str:
|
||||
""":obj:`str`: URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the
|
||||
result.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_url`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_url",
|
||||
new_attr_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_url
|
||||
|
||||
@property
|
||||
def thumb_mime_type(self) -> Optional[str]:
|
||||
""":obj:`str`: Optional. Optional. MIME type of the thumbnail, must be one of
|
||||
``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_mime_type`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_mime_type",
|
||||
new_attr_name="thumbnail_mime_type",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_mime_type
|
||||
|
||||
@@ -25,6 +25,10 @@ from telegram._messageentity import MessageEntity
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import JSONDict, ODVInput
|
||||
from telegram._utils.warnings_transition import (
|
||||
warn_about_deprecated_arg_return_new_arg,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
from telegram.constants import InlineQueryResultType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -45,7 +49,15 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
||||
:tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
|
||||
photo_url (:obj:`str`): A valid URL of the photo. Photo must be in JPEG format. Photo size
|
||||
must not exceed 5MB.
|
||||
thumb_url (:obj:`str`): URL of the thumbnail for the photo.
|
||||
thumbnail_url (:obj:`str`, optional): URL of the thumbnail for the photo.
|
||||
|
||||
Warning:
|
||||
The Bot API does **not** define this as an optional argument. It is formally
|
||||
optional for backwards compatibility with the deprecated :paramref:`thumb_url`.
|
||||
If you pass neither :paramref:`thumbnail_url` nor :paramref:`thumb_url`,
|
||||
:class:`ValueError` will be raised.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
photo_width (:obj:`int`, optional): Width of the photo.
|
||||
photo_height (:obj:`int`, optional): Height of the photo.
|
||||
title (:obj:`str`, optional): Title for the result.
|
||||
@@ -63,6 +75,14 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
||||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the photo.
|
||||
thumb_url (:obj:`str`, optional): URL of the thumbnail for the photo.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_url`.
|
||||
|
||||
Raises:
|
||||
:class:`ValueError`: If neither :paramref:`thumbnail_url` nor :paramref:`thumb_url` is
|
||||
supplied or if both are supplied and are not equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.PHOTO`.
|
||||
@@ -71,7 +91,7 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
||||
:tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
|
||||
photo_url (:obj:`str`): A valid URL of the photo. Photo must be in JPEG format. Photo size
|
||||
must not exceed 5MB.
|
||||
thumb_url (:obj:`str`): URL of the thumbnail for the photo.
|
||||
thumbnail_url (:obj:`str`): URL of the thumbnail for the photo.
|
||||
photo_width (:obj:`int`): Optional. Width of the photo.
|
||||
photo_height (:obj:`int`): Optional. Height of the photo.
|
||||
title (:obj:`str`): Optional. Title for the result.
|
||||
@@ -104,14 +124,17 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
||||
"parse_mode",
|
||||
"input_message_content",
|
||||
"photo_height",
|
||||
"thumb_url",
|
||||
"thumbnail_url",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id: str, # pylint: disable=redefined-builtin
|
||||
photo_url: str,
|
||||
thumb_url: str,
|
||||
# thumbnail_url is not optional in Telegram API, but we want to support thumb_url as well,
|
||||
# so thumbnail_url may not be passed. We will raise ValueError manually if neither
|
||||
# thumbnail_url nor thumb_url are passed
|
||||
thumbnail_url: str = None,
|
||||
photo_width: int = None,
|
||||
photo_height: int = None,
|
||||
title: str = None,
|
||||
@@ -121,14 +144,28 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
||||
input_message_content: "InputMessageContent" = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Sequence[MessageEntity] = None,
|
||||
# thumb_url is not optional in Telegram API, but it is here, along with thumbnail_url.
|
||||
thumb_url: str = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
if not (thumbnail_url or thumb_url):
|
||||
raise ValueError(
|
||||
"You must pass either 'thumbnail_url' or 'thumb_url'. Note that 'thumb_url' is "
|
||||
"deprecated."
|
||||
)
|
||||
|
||||
# Required
|
||||
super().__init__(InlineQueryResultType.PHOTO, id, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.photo_url: str = photo_url
|
||||
self.thumb_url: str = thumb_url
|
||||
self.thumbnail_url: str = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_url,
|
||||
new_arg=thumbnail_url,
|
||||
deprecated_arg_name="thumb_url",
|
||||
new_arg_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
|
||||
# Optionals
|
||||
self.photo_width: Optional[int] = photo_width
|
||||
@@ -140,3 +177,17 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
||||
self.caption_entities: Tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
|
||||
@property
|
||||
def thumb_url(self) -> Optional[str]:
|
||||
""":obj:`str`: URL of the thumbnail for the photo.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_url`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_url",
|
||||
new_attr_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_url
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# 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/].
|
||||
# pylint: disable=redefined-builtin
|
||||
"""This module contains the class that represent a Telegram InlineQueryResultsButton."""
|
||||
|
||||
from typing import TYPE_CHECKING, ClassVar, Optional
|
||||
|
||||
from telegram import constants
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._webappinfo import WebAppInfo
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class InlineQueryResultsButton(TelegramObject):
|
||||
"""This object represents a button to be shown above inline query results. You **must** use
|
||||
exactly one of the optional fields.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`text`, :attr:`web_app` and :attr:`start_parameter` are equal.
|
||||
|
||||
Args:
|
||||
text (:obj:`str`): Label text on the button.
|
||||
web_app (:class:`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 switch back to the inline mode
|
||||
using the method
|
||||
`switchInlineQuery <https://core.telegram.org/bots/webapps#initializing-web-apps>`_
|
||||
inside the Web App.
|
||||
start_parameter (:obj:`str`, optional): Deep-linking parameter for the
|
||||
:guilabel:`/start` message sent to the bot when user presses the switch button.
|
||||
:tg-const:`telegram.InlineQuery.MIN_SWITCH_PM_TEXT_LENGTH`-
|
||||
:tg-const:`telegram.InlineQuery.MAX_SWITCH_PM_TEXT_LENGTH` characters,
|
||||
only ``A-Z``, ``a-z``, ``0-9``, ``_`` and ``-`` are allowed.
|
||||
|
||||
Example:
|
||||
An inline bot that sends YouTube videos can ask the user to connect the bot to
|
||||
their YouTube account to adapt search results accordingly. To do this, it displays
|
||||
a 'Connect your YouTube account' button above the results, or even before showing
|
||||
any. The user presses the button, switches to a private chat with the bot and, in
|
||||
doing so, passes a start parameter that instructs the bot to return an OAuth link.
|
||||
Once done, the bot can offer a switch_inline button so that the user can easily
|
||||
return to the chat where they wanted to use the bot's inline capabilities.
|
||||
|
||||
Attributes:
|
||||
text (:obj:`str`): Label text on the button.
|
||||
web_app (:class:`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 switch back to the inline mode
|
||||
using the method ``web_app_switch_inline_query`` inside the Web App.
|
||||
start_parameter (:obj:`str`): Optional. Deep-linking parameter for the
|
||||
:guilabel:`/start` message sent to the bot when user presses the switch button.
|
||||
:tg-const:`telegram.InlineQuery.MIN_SWITCH_PM_TEXT_LENGTH`-
|
||||
:tg-const:`telegram.InlineQuery.MAX_SWITCH_PM_TEXT_LENGTH` characters,
|
||||
only ``A-Z``, ``a-z``, ``0-9``, ``_`` and ``-`` are allowed.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("text", "web_app", "start_parameter")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
text: str,
|
||||
web_app: WebAppInfo = None,
|
||||
start_parameter: str = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
# Required
|
||||
self.text: str = text
|
||||
|
||||
# Optional
|
||||
self.web_app: Optional[WebAppInfo] = web_app
|
||||
self.start_parameter: Optional[str] = start_parameter
|
||||
|
||||
self._id_attrs = (self.text, self.web_app, self.start_parameter)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["InlineQueryResultsButton"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
MIN_START_PARAMETER_LENGTH: ClassVar[
|
||||
int
|
||||
] = constants.InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH
|
||||
""":const:`telegram.constants.InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH`"""
|
||||
MAX_START_PARAMETER_LENGTH: ClassVar[
|
||||
int
|
||||
] = constants.InlineQueryResultsButtonLimit.MAX_START_PARAMETER_LENGTH
|
||||
""":const:`telegram.constants.InlineQueryResultsButtonLimit.MAX_START_PARAMETER_LENGTH`"""
|
||||
@@ -23,6 +23,10 @@ from typing import TYPE_CHECKING, Optional
|
||||
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
from telegram._inline.inlinequeryresult import InlineQueryResult
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings_transition import (
|
||||
warn_about_deprecated_arg_return_new_arg,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
from telegram.constants import InlineQueryResultType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -60,9 +64,27 @@ class InlineQueryResultVenue(InlineQueryResult):
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the venue.
|
||||
thumb_url (:obj:`str`, optional): Url of the thumbnail for the result.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_url`.
|
||||
thumb_width (:obj:`int`, optional): Thumbnail width.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_width`.
|
||||
thumb_height (:obj:`int`, optional): Thumbnail height.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_height`.
|
||||
thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_width (:obj:`int`, optional): Thumbnail width.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_height (:obj:`int`, optional): Thumbnail height.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VENUE`.
|
||||
id (:obj:`str`): Unique identifier for this result,
|
||||
@@ -84,9 +106,15 @@ class InlineQueryResultVenue(InlineQueryResult):
|
||||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
||||
message to be sent instead of the venue.
|
||||
thumb_url (:obj:`str`): Optional. Url of the thumbnail for the result.
|
||||
thumb_width (:obj:`int`): Optional. Thumbnail width.
|
||||
thumb_height (:obj:`int`): Optional. Thumbnail height.
|
||||
thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_width (:obj:`int`): Optional. Thumbnail width.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
thumbnail_height (:obj:`int`): Optional. Thumbnail height.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
"""
|
||||
|
||||
@@ -94,8 +122,8 @@ class InlineQueryResultVenue(InlineQueryResult):
|
||||
"longitude",
|
||||
"reply_markup",
|
||||
"google_place_type",
|
||||
"thumb_width",
|
||||
"thumb_height",
|
||||
"thumbnail_width",
|
||||
"thumbnail_height",
|
||||
"title",
|
||||
"address",
|
||||
"foursquare_id",
|
||||
@@ -103,7 +131,7 @@ class InlineQueryResultVenue(InlineQueryResult):
|
||||
"google_place_id",
|
||||
"input_message_content",
|
||||
"latitude",
|
||||
"thumb_url",
|
||||
"thumbnail_url",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@@ -122,6 +150,9 @@ class InlineQueryResultVenue(InlineQueryResult):
|
||||
thumb_height: int = None,
|
||||
google_place_id: str = None,
|
||||
google_place_type: str = None,
|
||||
thumbnail_url: str = None,
|
||||
thumbnail_width: int = None,
|
||||
thumbnail_height: int = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
@@ -140,6 +171,66 @@ class InlineQueryResultVenue(InlineQueryResult):
|
||||
self.google_place_type: Optional[str] = google_place_type
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.thumb_url: Optional[str] = thumb_url
|
||||
self.thumb_width: Optional[int] = thumb_width
|
||||
self.thumb_height: Optional[int] = thumb_height
|
||||
self.thumbnail_url: Optional[str] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_url,
|
||||
new_arg=thumbnail_url,
|
||||
deprecated_arg_name="thumb_url",
|
||||
new_arg_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
self.thumbnail_width: Optional[int] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_width,
|
||||
new_arg=thumbnail_width,
|
||||
deprecated_arg_name="thumb_width",
|
||||
new_arg_name="thumbnail_width",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
self.thumbnail_height: Optional[int] = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_height,
|
||||
new_arg=thumbnail_height,
|
||||
deprecated_arg_name="thumb_height",
|
||||
new_arg_name="thumbnail_height",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
|
||||
@property
|
||||
def thumb_url(self) -> Optional[str]:
|
||||
""":obj:`str`: Optional. Url of the thumbnail for the result.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_url`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_url",
|
||||
new_attr_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_url
|
||||
|
||||
@property
|
||||
def thumb_width(self) -> Optional[int]:
|
||||
""":obj:`str`: Optional. Thumbnail width.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_width`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_width",
|
||||
new_attr_name="thumbnail_width",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_width
|
||||
|
||||
@property
|
||||
def thumb_height(self) -> Optional[int]:
|
||||
""":obj:`str`: Optional. Thumbnail height.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_height`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_height",
|
||||
new_attr_name="thumbnail_height",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_height
|
||||
|
||||
@@ -25,6 +25,10 @@ from telegram._messageentity import MessageEntity
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import JSONDict, ODVInput
|
||||
from telegram._utils.warnings_transition import (
|
||||
warn_about_deprecated_arg_return_new_arg,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
from telegram.constants import InlineQueryResultType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -50,8 +54,22 @@ class InlineQueryResultVideo(InlineQueryResult):
|
||||
:tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
|
||||
video_url (:obj:`str`): A valid URL for the embedded video player or video file.
|
||||
mime_type (:obj:`str`): Mime type of the content of video url, "text/html" or "video/mp4".
|
||||
thumb_url (:obj:`str`): URL of the thumbnail (JPEG only) for the video.
|
||||
title (:obj:`str`): Title for the result.
|
||||
thumbnail_url (:obj:`str`, optional): URL of the thumbnail (JPEG only) for the video.
|
||||
|
||||
Warning:
|
||||
The Bot API does **not** define this as an optional argument. It is formally
|
||||
optional for backwards compatibility with the deprecated :paramref:`thumb_url`.
|
||||
If you pass neither :paramref:`thumbnail_url` nor :paramref:`thumb_url`,
|
||||
:class:`ValueError` will be raised.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
title (:obj:`str`, optional): Title for the result.
|
||||
|
||||
Warning:
|
||||
The Bot API does **not** define this as an optional argument. It is formally
|
||||
optional to ensure backwards compatibility of :paramref:`thumbnail_url` with the
|
||||
deprecated :paramref:`thumb_url`, which required that :paramref:`thumbnail_url`
|
||||
become optional. :class:`TypeError` will be raised if no ``title`` is passed.
|
||||
caption (:obj:`str`, optional): Caption of the video to be sent,
|
||||
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
|
||||
parsing.
|
||||
@@ -71,6 +89,15 @@ class InlineQueryResultVideo(InlineQueryResult):
|
||||
message to be sent instead of the video. This field is required if
|
||||
``InlineQueryResultVideo`` is used to send an HTML-page as a result
|
||||
(e.g., a YouTube video).
|
||||
thumb_url (:obj:`str`, optional): URL of the thumbnail (JPEG only) for the video.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbargumentdeprecation| :paramref:`thumbnail_url`.
|
||||
|
||||
Raises:
|
||||
:class:`ValueError`: If neither :paramref:`thumbnail_url` nor :paramref:`thumb_url` is
|
||||
supplied or if both are supplied and are not equal.
|
||||
:class:`TypeError`: If no :paramref:`title` is passed.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VIDEO`.
|
||||
@@ -79,7 +106,9 @@ class InlineQueryResultVideo(InlineQueryResult):
|
||||
:tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
|
||||
video_url (:obj:`str`): A valid URL for the embedded video player or video file.
|
||||
mime_type (:obj:`str`): Mime type of the content of video url, "text/html" or "video/mp4".
|
||||
thumb_url (:obj:`str`): URL of the thumbnail (JPEG only) for the video.
|
||||
thumbnail_url (:obj:`str`): URL of the thumbnail (JPEG only) for the video.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
title (:obj:`str`): Title for the result.
|
||||
caption (:obj:`str`): Optional. Caption of the video to be sent,
|
||||
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
|
||||
@@ -119,7 +148,7 @@ class InlineQueryResultVideo(InlineQueryResult):
|
||||
"input_message_content",
|
||||
"video_height",
|
||||
"video_width",
|
||||
"thumb_url",
|
||||
"thumbnail_url",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@@ -127,8 +156,13 @@ class InlineQueryResultVideo(InlineQueryResult):
|
||||
id: str, # pylint: disable=redefined-builtin
|
||||
video_url: str,
|
||||
mime_type: str,
|
||||
thumb_url: str,
|
||||
title: str,
|
||||
# thumbnail_url and title are not optional in Telegram API, but we want to support
|
||||
# thumb_url as well, so thumbnail_url may not be passed if thumb_url is passed.
|
||||
# We will raise ValueError manually if neither thumbnail_url nor thumb_url are passed.
|
||||
thumbnail_url: str = None,
|
||||
# title had to be made optional because of thumbnail_url. This is compensated by raising
|
||||
# TypeError manually if title is not passed.
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
video_width: int = None,
|
||||
video_height: int = None,
|
||||
@@ -138,15 +172,35 @@ class InlineQueryResultVideo(InlineQueryResult):
|
||||
input_message_content: "InputMessageContent" = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Sequence[MessageEntity] = None,
|
||||
# thumb_url is not optional in Telegram API, but it is here, along with thumbnail_url.
|
||||
thumb_url: str = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
if not (thumbnail_url or thumb_url):
|
||||
raise ValueError(
|
||||
"You must pass either 'thumbnail_url' or 'thumb_url'. Note that 'thumb_url' is "
|
||||
"deprecated."
|
||||
)
|
||||
|
||||
if title is None:
|
||||
raise TypeError(
|
||||
"InlineQueryResultVideo.__init__() missing a required argument: you forgot to pass"
|
||||
" either 'title' or 'thumbnail_url'."
|
||||
)
|
||||
|
||||
# Required
|
||||
super().__init__(InlineQueryResultType.VIDEO, id, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.video_url: str = video_url
|
||||
self.mime_type: str = mime_type
|
||||
self.thumb_url: str = thumb_url
|
||||
self.thumbnail_url: str = warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=thumb_url,
|
||||
new_arg=thumbnail_url,
|
||||
deprecated_arg_name="thumb_url",
|
||||
new_arg_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
self.title: str = title
|
||||
|
||||
# Optional
|
||||
@@ -159,3 +213,17 @@ class InlineQueryResultVideo(InlineQueryResult):
|
||||
self.description: Optional[str] = description
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
|
||||
@property
|
||||
def thumb_url(self) -> str:
|
||||
""":obj:`str`: URL of the thumbnail (JPEG only) for the video.
|
||||
|
||||
.. deprecated:: 20.2
|
||||
|thumbattributedeprecation| :attr:`thumbnail_url`.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="thumb_url",
|
||||
new_attr_name="thumbnail_url",
|
||||
bot_api_version="6.6",
|
||||
)
|
||||
return self.thumbnail_url
|
||||
|
||||
@@ -34,6 +34,10 @@ class KeyboardButtonRequestUser(TelegramObject):
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`request_id` is equal.
|
||||
|
||||
.. seealso::
|
||||
`Telegram Docs on requesting users \
|
||||
<https://core.telegram.org/bots/features#chat-and-user-selection>`_
|
||||
|
||||
.. versionadded:: 20.1
|
||||
|
||||
Args:
|
||||
@@ -87,6 +91,10 @@ class KeyboardButtonRequestChat(TelegramObject):
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`request_id` is equal.
|
||||
|
||||
.. seealso::
|
||||
`Telegram Docs on requesting chats \
|
||||
<https://core.telegram.org/bots/features#chat-and-user-selection>`_
|
||||
|
||||
.. versionadded:: 20.1
|
||||
|
||||
Args:
|
||||
|
||||
@@ -93,8 +93,7 @@ class MenuButton(TelegramObject):
|
||||
|
||||
if cls is MenuButton and data.get("type") in _class_mapping:
|
||||
return _class_mapping[data.pop("type")].de_json(data, bot=bot)
|
||||
out = super().de_json(data=data, bot=bot)
|
||||
return out
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
COMMANDS: ClassVar[str] = constants.MenuButtonType.COMMANDS
|
||||
""":const:`telegram.constants.MenuButtonType.COMMANDS`"""
|
||||
|
||||
+187
-156
@@ -19,7 +19,6 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Message."""
|
||||
import datetime
|
||||
import sys
|
||||
from html import escape
|
||||
from typing import TYPE_CHECKING, Dict, List, Optional, Sequence, Tuple, Union
|
||||
|
||||
@@ -57,9 +56,10 @@ from telegram._shared import ChatShared, UserShared
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.datetime import from_timestamp
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
|
||||
from telegram._utils.types import DVInput, FileInput, JSONDict, ODVInput, ReplyMarkup
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram._videochat import (
|
||||
VideoChatEnded,
|
||||
VideoChatParticipantsInvited,
|
||||
@@ -70,6 +70,7 @@ from telegram._webappdata import WebAppData
|
||||
from telegram._writeaccessallowed import WriteAccessAllowed
|
||||
from telegram.constants import MessageAttachmentType, ParseMode
|
||||
from telegram.helpers import escape_markdown
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import (
|
||||
@@ -122,6 +123,9 @@ class Message(TelegramObject):
|
||||
sent on behalf of a chat.
|
||||
date (:class:`datetime.datetime`): Date the message was sent in Unix time. Converted to
|
||||
:class:`datetime.datetime`.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
chat (:class:`telegram.Chat`): Conversation the message belongs to.
|
||||
forward_from (:class:`telegram.User`, optional): For forwarded messages, sender of
|
||||
the original message.
|
||||
@@ -133,6 +137,9 @@ class Message(TelegramObject):
|
||||
users who disallow adding a link to their account in forwarded messages.
|
||||
forward_date (:class:`datetime.datetime`, optional): For forwarded messages, date the
|
||||
original message was sent in Unix time. Converted to :class:`datetime.datetime`.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
is_automatic_forward (:obj:`bool`, optional): :obj:`True`, if the message is a channel
|
||||
post that was automatically forwarded to the connected discussion group.
|
||||
|
||||
@@ -142,6 +149,9 @@ class Message(TelegramObject):
|
||||
``reply_to_message`` fields even if it itself is a reply.
|
||||
edit_date (:class:`datetime.datetime`, optional): Date the message was last edited in Unix
|
||||
time. Converted to :class:`datetime.datetime`.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
has_protected_content (:obj:`bool`, optional): :obj:`True`, if the message can't be
|
||||
forwarded.
|
||||
|
||||
@@ -339,6 +349,9 @@ class Message(TelegramObject):
|
||||
sent on behalf of a chat.
|
||||
date (:class:`datetime.datetime`): Date the message was sent in Unix time. Converted to
|
||||
:class:`datetime.datetime`.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
chat (:class:`telegram.Chat`): Conversation the message belongs to.
|
||||
forward_from (:class:`telegram.User`): Optional. For forwarded messages, sender of the
|
||||
original message.
|
||||
@@ -348,6 +361,9 @@ class Message(TelegramObject):
|
||||
the original message in the channel.
|
||||
forward_date (:class:`datetime.datetime`): Optional. For forwarded messages, date the
|
||||
original message was sent in Unix time. Converted to :class:`datetime.datetime`.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
is_automatic_forward (:obj:`bool`): Optional. :obj:`True`, if the message is a channel
|
||||
post that was automatically forwarded to the connected discussion group.
|
||||
|
||||
@@ -357,6 +373,9 @@ class Message(TelegramObject):
|
||||
``reply_to_message`` fields even if it itself is a reply.
|
||||
edit_date (:class:`datetime.datetime`): Optional. Date the message was last edited in Unix
|
||||
time. Converted to :class:`datetime.datetime`.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
has_protected_content (:obj:`bool`): Optional. :obj:`True`, if the message can't be
|
||||
forwarded.
|
||||
|
||||
@@ -561,8 +580,13 @@ class Message(TelegramObject):
|
||||
|
||||
.. versionadded:: 20.1
|
||||
|
||||
.. |custom_emoji_formatting_note| replace:: Custom emoji entities will currently be ignored
|
||||
by this function. Instead, the supplied replacement for the emoji will be used.
|
||||
.. |custom_emoji_formatting_note| replace:: Custom emoji entities will be ignored by this
|
||||
function. Instead, the supplied replacement for the emoji will be used.
|
||||
|
||||
.. |custom_emoji_md1_deprecation| replace:: Since custom emoji entities are not supported by
|
||||
:attr:`~telegram.constants.ParseMode.MARKDOWN`, this method will raise a
|
||||
:exc:`ValueError` in future versions instead of falling back to the supplied replacement
|
||||
for the emoji.
|
||||
"""
|
||||
|
||||
# fmt: on
|
||||
@@ -827,14 +851,20 @@ class Message(TelegramObject):
|
||||
def link(self) -> Optional[str]:
|
||||
""":obj:`str`: Convenience property. If the chat of the message is not
|
||||
a private chat or normal group, returns a t.me link of the message.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
For messages that are replies or part of a forum topic, the link now points
|
||||
to the corresponding thread view.
|
||||
"""
|
||||
if self.chat.type not in [Chat.PRIVATE, Chat.GROUP]:
|
||||
if self.chat.username:
|
||||
to_link = self.chat.username
|
||||
else:
|
||||
# Get rid of leading -100 for supergroups
|
||||
to_link = f"c/{str(self.chat.id)[4:]}"
|
||||
return f"https://t.me/{to_link}/{self.message_id}"
|
||||
# the else block gets rid of leading -100 for supergroups:
|
||||
to_link = self.chat.username if self.chat.username else f"c/{str(self.chat.id)[4:]}"
|
||||
baselink = f"https://t.me/{to_link}/{self.message_id}"
|
||||
|
||||
# adds the thread for topics and replies
|
||||
if (self.is_topic_message and self.message_thread_id) or self.reply_to_message:
|
||||
baselink = f"{baselink}?thread={self.message_thread_id}"
|
||||
return baselink
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
@@ -845,17 +875,20 @@ class Message(TelegramObject):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["from_user"] = User.de_json(data.pop("from", None), bot)
|
||||
data["sender_chat"] = Chat.de_json(data.get("sender_chat"), bot)
|
||||
data["date"] = from_timestamp(data["date"])
|
||||
data["date"] = from_timestamp(data["date"], tzinfo=loc_tzinfo)
|
||||
data["chat"] = Chat.de_json(data.get("chat"), bot)
|
||||
data["entities"] = MessageEntity.de_list(data.get("entities"), bot)
|
||||
data["caption_entities"] = MessageEntity.de_list(data.get("caption_entities"), bot)
|
||||
data["forward_from"] = User.de_json(data.get("forward_from"), bot)
|
||||
data["forward_from_chat"] = Chat.de_json(data.get("forward_from_chat"), bot)
|
||||
data["forward_date"] = from_timestamp(data.get("forward_date"))
|
||||
data["forward_date"] = from_timestamp(data.get("forward_date"), tzinfo=loc_tzinfo)
|
||||
data["reply_to_message"] = Message.de_json(data.get("reply_to_message"), bot)
|
||||
data["edit_date"] = from_timestamp(data.get("edit_date"))
|
||||
data["edit_date"] = from_timestamp(data.get("edit_date"), tzinfo=loc_tzinfo)
|
||||
data["audio"] = Audio.de_json(data.get("audio"), bot)
|
||||
data["document"] = Document.de_json(data.get("document"), bot)
|
||||
data["animation"] = Animation.de_json(data.get("animation"), bot)
|
||||
@@ -1374,6 +1407,7 @@ class Message(TelegramObject):
|
||||
caption_entities: Sequence["MessageEntity"] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
quote: bool = None,
|
||||
@@ -1421,6 +1455,7 @@ class Message(TelegramObject):
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
|
||||
async def reply_document(
|
||||
@@ -1437,6 +1472,7 @@ class Message(TelegramObject):
|
||||
caption_entities: Sequence["MessageEntity"] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
quote: bool = None,
|
||||
@@ -1482,6 +1518,7 @@ class Message(TelegramObject):
|
||||
caption_entities=caption_entities,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
|
||||
async def reply_animation(
|
||||
@@ -1501,6 +1538,7 @@ class Message(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
has_spoiler: bool = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
quote: bool = None,
|
||||
@@ -1550,6 +1588,7 @@ class Message(TelegramObject):
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
|
||||
async def reply_sticker(
|
||||
@@ -1561,6 +1600,7 @@ class Message(TelegramObject):
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
emoji: str = None,
|
||||
*,
|
||||
quote: bool = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -1599,6 +1639,7 @@ class Message(TelegramObject):
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
emoji=emoji,
|
||||
)
|
||||
|
||||
async def reply_video(
|
||||
@@ -1619,6 +1660,7 @@ class Message(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
has_spoiler: bool = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
quote: bool = None,
|
||||
@@ -1668,6 +1710,7 @@ class Message(TelegramObject):
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
|
||||
async def reply_video_note(
|
||||
@@ -1682,6 +1725,7 @@ class Message(TelegramObject):
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
quote: bool = None,
|
||||
@@ -1726,6 +1770,7 @@ class Message(TelegramObject):
|
||||
filename=filename,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
|
||||
async def reply_voice(
|
||||
@@ -3125,10 +3170,6 @@ class Message(TelegramObject):
|
||||
if not self.text:
|
||||
raise RuntimeError("This Message has no 'text'.")
|
||||
|
||||
# Is it a narrow build, if so we don't need to convert
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
return self.text[entity.offset : entity.offset + entity.length]
|
||||
|
||||
entity_text = self.text.encode("utf-16-le")
|
||||
entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2]
|
||||
return entity_text.decode("utf-16-le")
|
||||
@@ -3155,10 +3196,6 @@ class Message(TelegramObject):
|
||||
if not self.caption:
|
||||
raise RuntimeError("This Message has no 'caption'.")
|
||||
|
||||
# Is it a narrow build, if so we don't need to convert
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
return self.caption[entity.offset : entity.offset + entity.length]
|
||||
|
||||
entity_text = self.caption.encode("utf-16-le")
|
||||
entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2]
|
||||
return entity_text.decode("utf-16-le")
|
||||
@@ -3235,8 +3272,7 @@ class Message(TelegramObject):
|
||||
if message_text is None:
|
||||
return None
|
||||
|
||||
if sys.maxunicode != 0xFFFF:
|
||||
message_text = message_text.encode("utf-16-le") # type: ignore
|
||||
message_text = message_text.encode("utf-16-le") # type: ignore
|
||||
|
||||
html_text = ""
|
||||
last_offset = 0
|
||||
@@ -3256,78 +3292,70 @@ class Message(TelegramObject):
|
||||
parsed_entities.extend(list(nested_entities.keys()))
|
||||
|
||||
orig_text = text
|
||||
text = escape(text)
|
||||
escaped_text = escape(text)
|
||||
|
||||
if nested_entities:
|
||||
text = Message._parse_html(
|
||||
escaped_text = Message._parse_html(
|
||||
orig_text, nested_entities, urled=urled, offset=entity.offset
|
||||
)
|
||||
|
||||
if entity.type == MessageEntity.TEXT_LINK:
|
||||
insert = f'<a href="{entity.url}">{text}</a>'
|
||||
insert = f'<a href="{entity.url}">{escaped_text}</a>'
|
||||
elif entity.type == MessageEntity.TEXT_MENTION and entity.user:
|
||||
insert = f'<a href="tg://user?id={entity.user.id}">{text}</a>'
|
||||
insert = f'<a href="tg://user?id={entity.user.id}">{escaped_text}</a>'
|
||||
elif entity.type == MessageEntity.URL and urled:
|
||||
insert = f'<a href="{text}">{text}</a>'
|
||||
insert = f'<a href="{escaped_text}">{escaped_text}</a>'
|
||||
elif entity.type == MessageEntity.BOLD:
|
||||
insert = f"<b>{text}</b>"
|
||||
insert = f"<b>{escaped_text}</b>"
|
||||
elif entity.type == MessageEntity.ITALIC:
|
||||
insert = f"<i>{text}</i>"
|
||||
insert = f"<i>{escaped_text}</i>"
|
||||
elif entity.type == MessageEntity.CODE:
|
||||
insert = f"<code>{text}</code>"
|
||||
insert = f"<code>{escaped_text}</code>"
|
||||
elif entity.type == MessageEntity.PRE:
|
||||
if entity.language:
|
||||
insert = f'<pre><code class="{entity.language}">{text}</code></pre>'
|
||||
insert = (
|
||||
f'<pre><code class="{entity.language}">{escaped_text}</code></pre>'
|
||||
)
|
||||
else:
|
||||
insert = f"<pre>{text}</pre>"
|
||||
insert = f"<pre>{escaped_text}</pre>"
|
||||
elif entity.type == MessageEntity.UNDERLINE:
|
||||
insert = f"<u>{text}</u>"
|
||||
insert = f"<u>{escaped_text}</u>"
|
||||
elif entity.type == MessageEntity.STRIKETHROUGH:
|
||||
insert = f"<s>{text}</s>"
|
||||
insert = f"<s>{escaped_text}</s>"
|
||||
elif entity.type == MessageEntity.SPOILER:
|
||||
insert = f'<span class="tg-spoiler">{text}</span>'
|
||||
insert = f'<span class="tg-spoiler">{escaped_text}</span>'
|
||||
elif entity.type == MessageEntity.CUSTOM_EMOJI:
|
||||
insert = (
|
||||
f'<tg-emoji emoji-id="{entity.custom_emoji_id}">{escaped_text}</tg-emoji>'
|
||||
)
|
||||
else:
|
||||
insert = text
|
||||
insert = escaped_text
|
||||
|
||||
if offset == 0:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
html_text += (
|
||||
escape(message_text[last_offset : entity.offset - offset]) + insert
|
||||
)
|
||||
else:
|
||||
html_text += (
|
||||
escape(
|
||||
message_text[ # type: ignore
|
||||
last_offset * 2 : (entity.offset - offset) * 2
|
||||
].decode("utf-16-le")
|
||||
)
|
||||
+ insert
|
||||
)
|
||||
else:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
html_text += message_text[last_offset : entity.offset - offset] + insert
|
||||
else:
|
||||
html_text += (
|
||||
html_text += (
|
||||
escape(
|
||||
message_text[ # type: ignore
|
||||
last_offset * 2 : (entity.offset - offset) * 2
|
||||
].decode("utf-16-le")
|
||||
+ insert
|
||||
)
|
||||
+ insert
|
||||
)
|
||||
else:
|
||||
html_text += (
|
||||
message_text[ # type: ignore
|
||||
last_offset * 2 : (entity.offset - offset) * 2
|
||||
].decode("utf-16-le")
|
||||
+ insert
|
||||
)
|
||||
|
||||
last_offset = entity.offset - offset + entity.length
|
||||
|
||||
if offset == 0:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
html_text += escape(message_text[last_offset:])
|
||||
else:
|
||||
html_text += escape(
|
||||
message_text[last_offset * 2 :].decode("utf-16-le") # type: ignore
|
||||
)
|
||||
html_text += escape(
|
||||
message_text[last_offset * 2 :].decode("utf-16-le") # type: ignore
|
||||
)
|
||||
else:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
html_text += message_text[last_offset:]
|
||||
else:
|
||||
html_text += message_text[last_offset * 2 :].decode("utf-16-le") # type: ignore
|
||||
html_text += message_text[last_offset * 2 :].decode("utf-16-le") # type: ignore
|
||||
|
||||
return html_text
|
||||
|
||||
@@ -3338,12 +3366,12 @@ class Message(TelegramObject):
|
||||
Use this if you want to retrieve the message text with the entities formatted as HTML in
|
||||
the same way the original message was formatted.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as HTML.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as HTML.
|
||||
|
||||
@@ -3357,12 +3385,12 @@ class Message(TelegramObject):
|
||||
Use this if you want to retrieve the message text with the entities formatted as HTML.
|
||||
This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as HTML.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as HTML.
|
||||
|
||||
@@ -3377,12 +3405,12 @@ class Message(TelegramObject):
|
||||
Use this if you want to retrieve the message caption with the caption entities formatted as
|
||||
HTML in the same way the original message was formatted.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as HTML.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as HTML.
|
||||
"""
|
||||
@@ -3396,12 +3424,12 @@ class Message(TelegramObject):
|
||||
Use this if you want to retrieve the message caption with the caption entities formatted as
|
||||
HTML. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as HTML.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as HTML.
|
||||
"""
|
||||
@@ -3420,8 +3448,7 @@ class Message(TelegramObject):
|
||||
if message_text is None:
|
||||
return None
|
||||
|
||||
if sys.maxunicode != 0xFFFF:
|
||||
message_text = message_text.encode("utf-16-le") # type: ignore
|
||||
message_text = message_text.encode("utf-16-le") # type: ignore
|
||||
|
||||
markdown_text = ""
|
||||
last_offset = 0
|
||||
@@ -3440,8 +3467,7 @@ class Message(TelegramObject):
|
||||
}
|
||||
parsed_entities.extend(list(nested_entities.keys()))
|
||||
|
||||
orig_text = text
|
||||
text = escape_markdown(text, version=version)
|
||||
escaped_text = escape_markdown(text, version=version)
|
||||
|
||||
if nested_entities:
|
||||
if version < 2:
|
||||
@@ -3449,8 +3475,8 @@ class Message(TelegramObject):
|
||||
"Nested entities are not supported for Markdown version 1"
|
||||
)
|
||||
|
||||
text = Message._parse_markdown(
|
||||
orig_text,
|
||||
escaped_text = Message._parse_markdown(
|
||||
text,
|
||||
nested_entities,
|
||||
urled=urled,
|
||||
offset=entity.offset,
|
||||
@@ -3465,105 +3491,98 @@ class Message(TelegramObject):
|
||||
url = escape_markdown(
|
||||
entity.url, version=version, entity_type=MessageEntity.TEXT_LINK
|
||||
)
|
||||
insert = f"[{text}]({url})"
|
||||
insert = f"[{escaped_text}]({url})"
|
||||
elif entity.type == MessageEntity.TEXT_MENTION and entity.user:
|
||||
insert = f"[{text}](tg://user?id={entity.user.id})"
|
||||
insert = f"[{escaped_text}](tg://user?id={entity.user.id})"
|
||||
elif entity.type == MessageEntity.URL and urled:
|
||||
if version == 1:
|
||||
link = orig_text
|
||||
else:
|
||||
link = text
|
||||
insert = f"[{link}]({orig_text})"
|
||||
link = text if version == 1 else escaped_text
|
||||
insert = f"[{link}]({text})"
|
||||
elif entity.type == MessageEntity.BOLD:
|
||||
insert = f"*{text}*"
|
||||
insert = f"*{escaped_text}*"
|
||||
elif entity.type == MessageEntity.ITALIC:
|
||||
insert = f"_{text}_"
|
||||
insert = f"_{escaped_text}_"
|
||||
elif entity.type == MessageEntity.CODE:
|
||||
# Monospace needs special escaping. Also can't have entities nested within
|
||||
insert = f"`{escape_markdown(orig_text, version, MessageEntity.CODE)}`"
|
||||
insert = f"`{escape_markdown(text, version, MessageEntity.CODE)}`"
|
||||
|
||||
elif entity.type == MessageEntity.PRE:
|
||||
# Monospace needs special escaping. Also can't have entities nested within
|
||||
code = escape_markdown(
|
||||
orig_text, version=version, entity_type=MessageEntity.PRE
|
||||
)
|
||||
code = escape_markdown(text, version=version, entity_type=MessageEntity.PRE)
|
||||
if entity.language:
|
||||
prefix = f"```{entity.language}\n"
|
||||
elif code.startswith("\\"):
|
||||
prefix = "```"
|
||||
else:
|
||||
if code.startswith("\\"):
|
||||
prefix = "```"
|
||||
else:
|
||||
prefix = "```\n"
|
||||
prefix = "```\n"
|
||||
insert = f"{prefix}{code}```"
|
||||
elif entity.type == MessageEntity.UNDERLINE:
|
||||
if version == 1:
|
||||
raise ValueError(
|
||||
"Underline entities are not supported for Markdown version 1"
|
||||
)
|
||||
insert = f"__{text}__"
|
||||
insert = f"__{escaped_text}__"
|
||||
elif entity.type == MessageEntity.STRIKETHROUGH:
|
||||
if version == 1:
|
||||
raise ValueError(
|
||||
"Strikethrough entities are not supported for Markdown version 1"
|
||||
)
|
||||
insert = f"~{text}~"
|
||||
insert = f"~{escaped_text}~"
|
||||
elif entity.type == MessageEntity.SPOILER:
|
||||
if version == 1:
|
||||
raise ValueError(
|
||||
"Spoiler entities are not supported for Markdown version 1"
|
||||
)
|
||||
insert = f"||{text}||"
|
||||
insert = f"||{escaped_text}||"
|
||||
elif entity.type == MessageEntity.CUSTOM_EMOJI:
|
||||
if version == 1:
|
||||
# this ensures compatibility to previous PTB versions
|
||||
insert = escaped_text
|
||||
warn(
|
||||
"Custom emoji entities are not supported for Markdown version 1. "
|
||||
"Future version of PTB will raise a ValueError instead of falling "
|
||||
"back to the alternative standard emoji.",
|
||||
stacklevel=3,
|
||||
category=PTBDeprecationWarning,
|
||||
)
|
||||
else:
|
||||
# This should never be needed because ids are numeric but the documentation
|
||||
# specifically mentions it so here we are
|
||||
custom_emoji_id = escape_markdown(
|
||||
entity.custom_emoji_id,
|
||||
version=version,
|
||||
entity_type=MessageEntity.CUSTOM_EMOJI,
|
||||
)
|
||||
insert = f""
|
||||
else:
|
||||
insert = text
|
||||
insert = escaped_text
|
||||
|
||||
if offset == 0:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
markdown_text += (
|
||||
escape_markdown(
|
||||
message_text[last_offset : entity.offset - offset], version=version
|
||||
)
|
||||
+ insert
|
||||
)
|
||||
else:
|
||||
markdown_text += (
|
||||
escape_markdown(
|
||||
message_text[ # type: ignore
|
||||
last_offset * 2 : (entity.offset - offset) * 2
|
||||
].decode("utf-16-le"),
|
||||
version=version,
|
||||
)
|
||||
+ insert
|
||||
)
|
||||
else:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
markdown_text += (
|
||||
message_text[last_offset : entity.offset - offset] + insert
|
||||
)
|
||||
else:
|
||||
markdown_text += (
|
||||
markdown_text += (
|
||||
escape_markdown(
|
||||
message_text[ # type: ignore
|
||||
last_offset * 2 : (entity.offset - offset) * 2
|
||||
].decode("utf-16-le")
|
||||
+ insert
|
||||
].decode("utf-16-le"),
|
||||
version=version,
|
||||
)
|
||||
+ insert
|
||||
)
|
||||
else:
|
||||
markdown_text += (
|
||||
message_text[ # type: ignore
|
||||
last_offset * 2 : (entity.offset - offset) * 2
|
||||
].decode("utf-16-le")
|
||||
+ insert
|
||||
)
|
||||
|
||||
last_offset = entity.offset - offset + entity.length
|
||||
|
||||
if offset == 0:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
markdown_text += escape_markdown(message_text[last_offset:], version=version)
|
||||
else:
|
||||
markdown_text += escape_markdown(
|
||||
message_text[last_offset * 2 :].decode("utf-16-le"), # type: ignore
|
||||
version=version,
|
||||
)
|
||||
markdown_text += escape_markdown(
|
||||
message_text[last_offset * 2 :].decode("utf-16-le"), # type: ignore
|
||||
version=version,
|
||||
)
|
||||
else:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
markdown_text += message_text[last_offset:]
|
||||
else:
|
||||
markdown_text += message_text[last_offset * 2 :].decode( # type: ignore
|
||||
"utf-16-le"
|
||||
)
|
||||
markdown_text += message_text[last_offset * 2 :].decode("utf-16-le") # type: ignore
|
||||
|
||||
return markdown_text
|
||||
|
||||
@@ -3582,6 +3601,9 @@ class Message(TelegramObject):
|
||||
|
||||
* |custom_emoji_formatting_note|
|
||||
|
||||
.. deprecated:: 20.3
|
||||
|custom_emoji_md1_deprecation|
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as Markdown.
|
||||
|
||||
@@ -3600,12 +3622,12 @@ class Message(TelegramObject):
|
||||
Use this if you want to retrieve the message text with the entities formatted as Markdown
|
||||
in the same way the original message was formatted.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as Markdown V2.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as Markdown.
|
||||
"""
|
||||
@@ -3626,6 +3648,9 @@ class Message(TelegramObject):
|
||||
|
||||
* |custom_emoji_formatting_note|
|
||||
|
||||
.. deprecated:: 20.3
|
||||
|custom_emoji_md1_deprecation|
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as Markdown.
|
||||
|
||||
@@ -3644,12 +3669,12 @@ class Message(TelegramObject):
|
||||
Use this if you want to retrieve the message text with the entities formatted as Markdown.
|
||||
This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as Markdown V2.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as Markdown.
|
||||
"""
|
||||
@@ -3670,6 +3695,9 @@ class Message(TelegramObject):
|
||||
|
||||
* |custom_emoji_formatting_note|
|
||||
|
||||
.. deprecated:: 20.3
|
||||
|custom_emoji_md1_deprecation|
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as Markdown.
|
||||
|
||||
@@ -3688,12 +3716,12 @@ class Message(TelegramObject):
|
||||
Use this if you want to retrieve the message caption with the caption entities formatted as
|
||||
Markdown in the same way the original message was formatted.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as Markdown V2.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as Markdown.
|
||||
"""
|
||||
@@ -3716,6 +3744,9 @@ class Message(TelegramObject):
|
||||
|
||||
* |custom_emoji_formatting_note|
|
||||
|
||||
.. deprecated:: 20.3
|
||||
|custom_emoji_md1_deprecation|
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as Markdown.
|
||||
|
||||
@@ -3734,12 +3765,12 @@ class Message(TelegramObject):
|
||||
Use this if you want to retrieve the message caption with the caption entities formatted as
|
||||
Markdown. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as Markdown V2.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as Markdown.
|
||||
"""
|
||||
|
||||
@@ -180,7 +180,7 @@ class PassportElementErrorFiles(PassportElementError):
|
||||
with self._unfrozen():
|
||||
self.file_hashes: str = file_hashes
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.message) + tuple(file_hashes)
|
||||
self._id_attrs = (self.source, self.type, self.message, *tuple(file_hashes))
|
||||
|
||||
|
||||
class PassportElementErrorFrontSide(PassportElementError):
|
||||
@@ -362,7 +362,7 @@ class PassportElementErrorTranslationFiles(PassportElementError):
|
||||
with self._unfrozen():
|
||||
self.file_hashes: str = file_hashes
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.message) + tuple(file_hashes)
|
||||
self._id_attrs = (self.source, self.type, self.message, *tuple(file_hashes))
|
||||
|
||||
|
||||
class PassportElementErrorUnspecified(PassportElementError):
|
||||
|
||||
@@ -24,7 +24,7 @@ from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import LabeledPrice # noqa
|
||||
from telegram import LabeledPrice
|
||||
|
||||
|
||||
class ShippingOption(TelegramObject):
|
||||
|
||||
+11
-6
@@ -18,7 +18,6 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Poll."""
|
||||
import datetime
|
||||
import sys
|
||||
from typing import TYPE_CHECKING, ClassVar, Dict, List, Optional, Sequence, Tuple
|
||||
|
||||
from telegram import constants
|
||||
@@ -27,7 +26,7 @@ from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils import enum
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.datetime import from_timestamp
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -174,6 +173,9 @@ class Poll(TelegramObject):
|
||||
close_date (:obj:`datetime.datetime`, optional): Point in time (Unix timestamp) when the
|
||||
poll will be automatically closed. Converted to :obj:`datetime.datetime`.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
|
||||
Attributes:
|
||||
id (:obj:`str`): Unique poll identifier.
|
||||
question (:obj:`str`): Poll question, :tg-const:`telegram.Poll.MIN_QUESTION_LENGTH`-
|
||||
@@ -207,6 +209,9 @@ class Poll(TelegramObject):
|
||||
close_date (:obj:`datetime.datetime`): Optional. Point in time when the poll will be
|
||||
automatically closed.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
@@ -272,9 +277,12 @@ class Poll(TelegramObject):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["options"] = [PollOption.de_json(option, bot) for option in data["options"]]
|
||||
data["explanation_entities"] = MessageEntity.de_list(data.get("explanation_entities"), bot)
|
||||
data["close_date"] = from_timestamp(data.get("close_date"))
|
||||
data["close_date"] = from_timestamp(data.get("close_date"), tzinfo=loc_tzinfo)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -300,9 +308,6 @@ class Poll(TelegramObject):
|
||||
if not self.explanation:
|
||||
raise RuntimeError("This Poll has no 'explanation'.")
|
||||
|
||||
# Is it a narrow build, if so we don't need to convert
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
return self.explanation[entity.offset : entity.offset + entity.length]
|
||||
entity_text = self.explanation.encode("utf-16-le")
|
||||
entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2]
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# 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
|
||||
"""This module contains a class that represents a Telegram SwitchInlineQueryChosenChat."""
|
||||
from typing import Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class SwitchInlineQueryChosenChat(TelegramObject):
|
||||
"""
|
||||
This object represents an inline button that switches the current user to inline mode in a
|
||||
chosen chat, with an optional default inline query.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`query`, :attr:`allow_user_chats`, :attr:`allow_bot_chats`,
|
||||
:attr:`allow_group_chats`, and :attr:`allow_channel_chats` are equal.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
|
||||
Caution:
|
||||
The PTB team has discovered that you must pass at least one of
|
||||
:paramref:`allow_user_chats`, :paramref:`allow_bot_chats`, :paramref:`allow_group_chats`,
|
||||
or :paramref:`allow_channel_chats` to Telegram. Otherwise, an error will be raised.
|
||||
|
||||
Args:
|
||||
query (:obj:`str`, optional): The default inline query to be inserted in the input field.
|
||||
If left empty, only the bot's username will be inserted.
|
||||
allow_user_chats (:obj:`bool`, optional): Pass :obj:`True`, if private chats with users
|
||||
can be chosen.
|
||||
allow_bot_chats (:obj:`bool`, optional): Pass :obj:`True`, if private chats with bots can
|
||||
be chosen.
|
||||
allow_group_chats (:obj:`bool`, optional): Pass :obj:`True`, if group and supergroup chats
|
||||
can be chosen.
|
||||
allow_channel_chats (:obj:`bool`, optional): Pass :obj:`True`, if channel chats can be
|
||||
chosen.
|
||||
|
||||
Attributes:
|
||||
query (:obj:`str`): Optional. The default inline query to be inserted in the input field.
|
||||
If left empty, only the bot's username will be inserted.
|
||||
allow_user_chats (:obj:`bool`): Optional. :obj:`True`, if private chats with users can be
|
||||
chosen.
|
||||
allow_bot_chats (:obj:`bool`): Optional. :obj:`True`, if private chats with bots can be
|
||||
chosen.
|
||||
allow_group_chats (:obj:`bool`): Optional. :obj:`True`, if group and supergroup chats can
|
||||
be chosen.
|
||||
allow_channel_chats (:obj:`bool`): Optional. :obj:`True`, if channel chats can be chosen.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"query",
|
||||
"allow_user_chats",
|
||||
"allow_bot_chats",
|
||||
"allow_group_chats",
|
||||
"allow_channel_chats",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
query: str = None,
|
||||
allow_user_chats: bool = None,
|
||||
allow_bot_chats: bool = None,
|
||||
allow_group_chats: bool = None,
|
||||
allow_channel_chats: bool = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Optional
|
||||
self.query: Optional[str] = query
|
||||
self.allow_user_chats: Optional[bool] = allow_user_chats
|
||||
self.allow_bot_chats: Optional[bool] = allow_bot_chats
|
||||
self.allow_group_chats: Optional[bool] = allow_group_chats
|
||||
self.allow_channel_chats: Optional[bool] = allow_channel_chats
|
||||
|
||||
self._id_attrs = (
|
||||
self.query,
|
||||
self.allow_user_chats,
|
||||
self.allow_bot_chats,
|
||||
self.allow_group_chats,
|
||||
self.allow_channel_chats,
|
||||
)
|
||||
|
||||
self._freeze()
|
||||
@@ -58,6 +58,12 @@ class TelegramObject:
|
||||
The :mod:`pickle` and :func:`~copy.deepcopy` behavior of objects of this type are defined by
|
||||
:meth:`__getstate__`, :meth:`__setstate__` and :meth:`__deepcopy__`.
|
||||
|
||||
Tip:
|
||||
Objects of this type can be serialized via Python's :mod:`pickle` module and pickled
|
||||
objects from one version of PTB are usually loadable in future versions. However, we can
|
||||
not guarantee that this compatibility will always be provided. At least a manual one-time
|
||||
conversion of the data may be needed on major updates of the library.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
||||
* Removed argument and attribute ``bot`` for several subclasses. Use
|
||||
@@ -281,7 +287,7 @@ class TelegramObject:
|
||||
|
||||
# Make sure that we have a `_bot` attribute. This is necessary, since __getstate__ omits
|
||||
# this as Bots are not pickable.
|
||||
setattr(self, "_bot", None)
|
||||
self._bot = None
|
||||
|
||||
# get api_kwargs first because we may need to add entries to it (see try-except below)
|
||||
api_kwargs = cast(Dict[str, object], state.pop("api_kwargs", {}))
|
||||
@@ -299,7 +305,7 @@ class TelegramObject:
|
||||
# and then set the rest as MappingProxyType attribute. Converting to MappingProxyType
|
||||
# is necessary, since __getstate__ converts it to a dict as MPT is not pickable.
|
||||
self._apply_api_kwargs(api_kwargs)
|
||||
setattr(self, "api_kwargs", MappingProxyType(api_kwargs))
|
||||
self.api_kwargs = MappingProxyType(api_kwargs)
|
||||
|
||||
# Apply freezing if necessary
|
||||
# we .get(…) the setting for backwards compatibility with objects that were pickled
|
||||
@@ -328,7 +334,7 @@ class TelegramObject:
|
||||
result = cls.__new__(cls) # create a new instance
|
||||
memodict[id(self)] = result # save the id of the object in the dict
|
||||
|
||||
setattr(result, "_frozen", False) # unfreeze the new object for setting the attributes
|
||||
result._frozen = False # unfreeze the new object for setting the attributes
|
||||
|
||||
# now we set the attributes in the deepcopied object
|
||||
for k in self._get_attrs_names(include_private=True):
|
||||
|
||||
+2
-2
@@ -34,7 +34,7 @@ from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, Chat, User # noqa
|
||||
from telegram import Bot, Chat, User
|
||||
|
||||
|
||||
class Update(TelegramObject):
|
||||
@@ -46,7 +46,7 @@ class Update(TelegramObject):
|
||||
Note:
|
||||
At most one of the optional parameters can be present in any given update.
|
||||
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions-–-Your-first-Bot>`
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions---Your-first-Bot>`
|
||||
|
||||
Args:
|
||||
update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a
|
||||
|
||||
@@ -553,6 +553,7 @@ class User(TelegramObject):
|
||||
caption_entities: Sequence["MessageEntity"] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -596,6 +597,7 @@ class User(TelegramObject):
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
|
||||
async def send_chat_action(
|
||||
@@ -748,6 +750,7 @@ class User(TelegramObject):
|
||||
caption_entities: Sequence["MessageEntity"] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -783,6 +786,7 @@ class User(TelegramObject):
|
||||
pool_timeout=pool_timeout,
|
||||
parse_mode=parse_mode,
|
||||
thumb=thumb,
|
||||
thumbnail=thumbnail,
|
||||
api_kwargs=api_kwargs,
|
||||
disable_content_type_detection=disable_content_type_detection,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
@@ -1005,6 +1009,7 @@ class User(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
has_spoiler: bool = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -1049,6 +1054,7 @@ class User(TelegramObject):
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
|
||||
async def send_sticker(
|
||||
@@ -1060,6 +1066,7 @@ class User(TelegramObject):
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
emoji: str = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
@@ -1094,6 +1101,7 @@ class User(TelegramObject):
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
emoji=emoji,
|
||||
)
|
||||
|
||||
async def send_video(
|
||||
@@ -1114,6 +1122,7 @@ class User(TelegramObject):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
has_spoiler: bool = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -1152,6 +1161,7 @@ class User(TelegramObject):
|
||||
parse_mode=parse_mode,
|
||||
supports_streaming=supports_streaming,
|
||||
thumb=thumb,
|
||||
thumbnail=thumbnail,
|
||||
api_kwargs=api_kwargs,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
caption_entities=caption_entities,
|
||||
@@ -1234,6 +1244,7 @@ class User(TelegramObject):
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -1273,6 +1284,7 @@ class User(TelegramObject):
|
||||
filename=filename,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
|
||||
async def send_voice(
|
||||
|
||||
@@ -29,7 +29,10 @@ Warning:
|
||||
"""
|
||||
import datetime as dtm # skipcq: PYL-W0406
|
||||
import time
|
||||
from typing import Optional, Union
|
||||
from typing import TYPE_CHECKING, Optional, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
# pytz is only available if it was installed as dependency of APScheduler, so we make a little
|
||||
# workaround here
|
||||
@@ -162,7 +165,10 @@ def to_timestamp(
|
||||
)
|
||||
|
||||
|
||||
def from_timestamp(unixtime: Optional[int], tzinfo: dtm.tzinfo = UTC) -> Optional[dtm.datetime]:
|
||||
def from_timestamp(
|
||||
unixtime: Optional[int],
|
||||
tzinfo: Optional[dtm.tzinfo] = None,
|
||||
) -> Optional[dtm.datetime]:
|
||||
"""
|
||||
Converts an (integer) unix timestamp to a timezone aware datetime object.
|
||||
:obj:`None` s are left alone (i.e. ``from_timestamp(None)`` is :obj:`None`).
|
||||
@@ -170,7 +176,8 @@ def from_timestamp(unixtime: Optional[int], tzinfo: dtm.tzinfo = UTC) -> Optiona
|
||||
Args:
|
||||
unixtime (:obj:`int`): Integer POSIX timestamp.
|
||||
tzinfo (:obj:`datetime.tzinfo`, optional): The timezone to which the timestamp is to be
|
||||
converted to. Defaults to UTC.
|
||||
converted to. Defaults to :obj:`None`, in which case the returned datetime object will
|
||||
be timezone aware and in UTC.
|
||||
|
||||
Returns:
|
||||
Timezone aware equivalent :obj:`datetime.datetime` value if :paramref:`unixtime` is not
|
||||
@@ -179,9 +186,19 @@ def from_timestamp(unixtime: Optional[int], tzinfo: dtm.tzinfo = UTC) -> Optiona
|
||||
if unixtime is None:
|
||||
return None
|
||||
|
||||
if tzinfo is not None:
|
||||
return dtm.datetime.fromtimestamp(unixtime, tz=tzinfo)
|
||||
return dtm.datetime.utcfromtimestamp(unixtime)
|
||||
return dtm.datetime.fromtimestamp(unixtime, tz=UTC if tzinfo is None else tzinfo)
|
||||
|
||||
|
||||
def extract_tzinfo_from_defaults(bot: "Bot") -> Union[dtm.tzinfo, None]:
|
||||
"""
|
||||
Extracts the timezone info from the default values of the bot.
|
||||
If the bot has no default values, :obj:`None` is returned.
|
||||
"""
|
||||
# We don't use `ininstance(bot, ExtBot)` here so that this works
|
||||
# in `python-telegram-bot-raw` as well
|
||||
if hasattr(bot, "defaults") and bot.defaults:
|
||||
return bot.defaults.tzinfo
|
||||
return None
|
||||
|
||||
|
||||
def _datetime_to_float_timestamp(dt_obj: dtm.datetime) -> float:
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# 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 helper functions related to logging.
|
||||
|
||||
Warning:
|
||||
Contents of this module are intended to be used internally by the library and *not* by the
|
||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
||||
the changelog.
|
||||
"""
|
||||
import logging
|
||||
|
||||
|
||||
def get_logger(file_name: str, class_name: str = None) -> logging.Logger:
|
||||
"""Returns a logger with an appropriate name.
|
||||
Use as follows::
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
If for example `__name__` is `telegram.ext._updater`, the logger will be named
|
||||
`telegram.ext.Updater`. If `class_name` is passed, this will result in
|
||||
`telegram.ext.<class_name>`. Useful e.g. for CamelCase class names.
|
||||
|
||||
If the file name points to a utils module, the logger name will simply be `telegram(.ext)`.
|
||||
|
||||
Returns:
|
||||
:class:`logging.Logger`: The logger.
|
||||
"""
|
||||
parts = file_name.split("_")
|
||||
if parts[1].startswith("utils") and class_name is None:
|
||||
name = parts[0].rstrip(".")
|
||||
else:
|
||||
name = f"{parts[0]}{class_name or parts[1].capitalize()}"
|
||||
return logging.getLogger(name)
|
||||
@@ -60,7 +60,7 @@ DVInput = Union["DefaultValue[DVValueType]", DVValueType, "DefaultValue[None]"]
|
||||
as ``Union[DefaultValue[type], type, DefaultValue[None]]``."""
|
||||
|
||||
RT = TypeVar("RT")
|
||||
SCT = Union[RT, Collection[RT]]
|
||||
SCT = Union[RT, Collection[RT]] # pylint: disable=invalid-name
|
||||
"""Single instance or collection of instances."""
|
||||
|
||||
ReplyMarkup = Union[
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# 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 functionality used for transition warnings issued by this library.
|
||||
|
||||
It was created to prevent circular imports that would be caused by creating the warnings
|
||||
inside warnings.py.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
from typing import Any, Callable, Type
|
||||
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
|
||||
# Narrower type hints will cause linting errors and/or circular imports.
|
||||
# We'll use `Any` here and put type hints in the calling code.
|
||||
def warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg: Any,
|
||||
new_arg: Any,
|
||||
deprecated_arg_name: str,
|
||||
new_arg_name: str,
|
||||
bot_api_version: str,
|
||||
stacklevel: int = 2,
|
||||
warn_callback: Callable[[str, Type[Warning], int], None] = warn,
|
||||
) -> Any:
|
||||
"""A helper function for the transition in API when argument is renamed.
|
||||
|
||||
Checks the `deprecated_arg` and `new_arg` objects; warns if non-None `deprecated_arg` object
|
||||
was passed. Returns `new_arg` object (either the one originally passed by the user or the one
|
||||
that user passed as `deprecated_arg`).
|
||||
|
||||
Raises `ValueError` if both `deprecated_arg` and `new_arg` objects were passed, and they are
|
||||
different.
|
||||
"""
|
||||
if deprecated_arg and new_arg and deprecated_arg != new_arg:
|
||||
raise ValueError(
|
||||
f"You passed different entities as '{deprecated_arg_name}' and '{new_arg_name}'. "
|
||||
f"The parameter '{deprecated_arg_name}' was renamed to '{new_arg_name}' in Bot API "
|
||||
f"{bot_api_version}. We recommend using '{new_arg_name}' instead of "
|
||||
f"'{deprecated_arg_name}'."
|
||||
)
|
||||
|
||||
if deprecated_arg:
|
||||
warn_callback(
|
||||
f"Bot API {bot_api_version} renamed the argument '{deprecated_arg_name}' to "
|
||||
f"'{new_arg_name}'.",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel + 1,
|
||||
)
|
||||
return deprecated_arg
|
||||
|
||||
return new_arg
|
||||
|
||||
|
||||
def warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name: str,
|
||||
new_attr_name: str,
|
||||
bot_api_version: str,
|
||||
stacklevel: int = 2,
|
||||
) -> None:
|
||||
"""A helper function for the transition in API when attribute is renamed. Call from properties.
|
||||
|
||||
The properties replace deprecated attributes in classes and issue these deprecation warnings.
|
||||
"""
|
||||
warn(
|
||||
f"Bot API {bot_api_version} renamed the attribute '{deprecated_attr_name}' to "
|
||||
f"'{new_attr_name}'.",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel=stacklevel + 1,
|
||||
)
|
||||
|
||||
|
||||
def warn_about_thumb_return_thumbnail(
|
||||
deprecated_arg: Any,
|
||||
new_arg: Any,
|
||||
stacklevel: int = 2,
|
||||
warn_callback: Callable[[str, Type[Warning], int], None] = warn,
|
||||
) -> Any:
|
||||
"""A helper function to warn about using a deprecated 'thumb' argument and return it or the
|
||||
new 'thumbnail' argument, introduced in API 6.6.
|
||||
"""
|
||||
return warn_about_deprecated_arg_return_new_arg(
|
||||
deprecated_arg=deprecated_arg,
|
||||
new_arg=new_arg,
|
||||
warn_callback=warn_callback,
|
||||
deprecated_arg_name="thumb",
|
||||
new_arg_name="thumbnail",
|
||||
bot_api_version="6.6",
|
||||
stacklevel=stacklevel + 1,
|
||||
)
|
||||
@@ -50,7 +50,7 @@ class Version(NamedTuple):
|
||||
return version
|
||||
|
||||
|
||||
__version_info__ = Version(major=20, minor=1, micro=0, releaselevel="final", serial=0)
|
||||
__version_info__ = Version(major=20, minor=3, micro=0, releaselevel="final", serial=0)
|
||||
__version__ = str(__version_info__)
|
||||
|
||||
# # SETUP.PY MARKER
|
||||
|
||||
+11
-2
@@ -23,7 +23,7 @@ from typing import TYPE_CHECKING, Optional, Sequence, Tuple
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.datetime import from_timestamp
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -149,10 +149,16 @@ class VideoChatScheduled(TelegramObject):
|
||||
Args:
|
||||
start_date (:obj:`datetime.datetime`): Point in time (Unix timestamp) when the video
|
||||
chat is supposed to be started by a chat administrator
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
Attributes:
|
||||
start_date (:obj:`datetime.datetime`): Point in time (Unix timestamp) when the video
|
||||
chat is supposed to be started by a chat administrator
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("start_date",)
|
||||
@@ -178,6 +184,9 @@ class VideoChatScheduled(TelegramObject):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["start_date"] = from_timestamp(data["start_date"])
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["start_date"] = from_timestamp(data["start_date"], tzinfo=loc_tzinfo)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
+28
-11
@@ -21,7 +21,7 @@ from typing import TYPE_CHECKING, Optional, Sequence, Tuple
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.datetime import from_timestamp
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -49,8 +49,11 @@ class WebhookInfo(TelegramObject):
|
||||
webhook certificate checks.
|
||||
pending_update_count (:obj:`int`): Number of updates awaiting delivery.
|
||||
ip_address (:obj:`str`, optional): Currently used webhook IP address.
|
||||
last_error_date (:obj:`int`, optional): Unix time for the most recent error that happened
|
||||
when trying to deliver an update via webhook.
|
||||
last_error_date (:class:`datetime.datetime`): Optional. Datetime for the most recent
|
||||
error that happened when trying to deliver an update via webhook.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
last_error_message (:obj:`str`, optional): Error message in human-readable format for the
|
||||
most recent error that happened when trying to deliver an update via webhook.
|
||||
max_connections (:obj:`int`, optional): Maximum allowed number of simultaneous HTTPS
|
||||
@@ -62,18 +65,25 @@ class WebhookInfo(TelegramObject):
|
||||
.. versionchanged:: 20.0
|
||||
|sequenceclassargs|
|
||||
|
||||
last_synchronization_error_date (:obj:`int`, optional): Unix time of the most recent error
|
||||
that happened when trying to synchronize available updates with Telegram datacenters.
|
||||
last_synchronization_error_date (:class:`datetime.datetime`, optional): Datetime of the
|
||||
most recent error that happened when trying to synchronize available updates with
|
||||
Telegram datacenters.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
Attributes:
|
||||
url (:obj:`str`): Webhook URL, may be empty if webhook is not set up.
|
||||
has_custom_certificate (:obj:`bool`): :obj:`True`, if a custom certificate was provided for
|
||||
webhook certificate checks.
|
||||
pending_update_count (:obj:`int`): Number of updates awaiting delivery.
|
||||
ip_address (:obj:`str`): Optional. Currently used webhook IP address.
|
||||
last_error_date (:obj:`int`): Optional. Unix time for the most recent error that happened
|
||||
when trying to deliver an update via webhook.
|
||||
last_error_date (:class:`datetime.datetime`): Optional. Datetime for the most recent
|
||||
error that happened when trying to deliver an update via webhook.
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
last_error_message (:obj:`str`): Optional. Error message in human-readable format for the
|
||||
most recent error that happened when trying to deliver an update via webhook.
|
||||
max_connections (:obj:`int`): Optional. Maximum allowed number of simultaneous HTTPS
|
||||
@@ -86,10 +96,14 @@ class WebhookInfo(TelegramObject):
|
||||
|
||||
* |tupleclassattrs|
|
||||
* |alwaystuple|
|
||||
last_synchronization_error_date (:obj:`int`): Optional. Unix time of the most recent error
|
||||
that happened when trying to synchronize available updates with Telegram datacenters.
|
||||
last_synchronization_error_date (:class:`datetime.datetime`, optional): Datetime of the
|
||||
most recent error that happened when trying to synchronize available updates with
|
||||
Telegram datacenters.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
|
||||
.. versionchanged:: 20.3
|
||||
|datetime_localization|
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
@@ -154,9 +168,12 @@ class WebhookInfo(TelegramObject):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["last_error_date"] = from_timestamp(data.get("last_error_date"))
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["last_error_date"] = from_timestamp(data.get("last_error_date"), tzinfo=loc_tzinfo)
|
||||
data["last_synchronization_error_date"] = from_timestamp(
|
||||
data.get("last_synchronization_error_date")
|
||||
data.get("last_synchronization_error_date"), tzinfo=loc_tzinfo
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -17,21 +17,35 @@
|
||||
# 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 the write access allowed service message."""
|
||||
from typing import Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class WriteAccessAllowed(TelegramObject):
|
||||
"""
|
||||
This object represents a service message about a user allowing a bot added to the attachment
|
||||
menu to write messages. Currently holds no information.
|
||||
This object represents a service message about a user allowing a bot to write messages after
|
||||
adding the bot to the attachment menu or launching a Web App from a link.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
|
||||
Args:
|
||||
web_app_name (:obj:`str`, optional): Name of the Web App which was launched from a link.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
|
||||
Attributes:
|
||||
web_app_name (:obj:`str`): Optional. Name of the Web App which was launched from a link.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
__slots__ = ("web_app_name",)
|
||||
|
||||
def __init__(self, *, api_kwargs: JSONDict = None):
|
||||
def __init__(self, web_app_name: str = None, *, api_kwargs: JSONDict = None):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.web_app_name: Optional[str] = web_app_name
|
||||
|
||||
self._freeze()
|
||||
|
||||
+164
-4
@@ -36,6 +36,8 @@ __all__ = [
|
||||
"BOT_API_VERSION_INFO",
|
||||
"BotCommandLimit",
|
||||
"BotCommandScopeType",
|
||||
"BotDescriptionLimit",
|
||||
"BotNameLimit",
|
||||
"CallbackQueryLimit",
|
||||
"ChatAction",
|
||||
"ChatID",
|
||||
@@ -56,6 +58,7 @@ __all__ = [
|
||||
"InlineKeyboardMarkupLimit",
|
||||
"InlineQueryLimit",
|
||||
"InlineQueryResultLimit",
|
||||
"InlineQueryResultsButtonLimit",
|
||||
"InlineQueryResultType",
|
||||
"InputMediaType",
|
||||
"InvoiceLimit",
|
||||
@@ -73,7 +76,9 @@ __all__ = [
|
||||
"PollType",
|
||||
"ReplyLimit",
|
||||
"SUPPORTED_WEBHOOK_PORTS",
|
||||
"StickerFormat",
|
||||
"StickerLimit",
|
||||
"StickerSetLimit",
|
||||
"StickerType",
|
||||
"WebhookLimit",
|
||||
"UpdateType",
|
||||
@@ -111,7 +116,7 @@ class _BotAPIVersion(NamedTuple):
|
||||
#: :data:`telegram.__bot_api_version_info__`.
|
||||
#:
|
||||
#: .. versionadded:: 20.0
|
||||
BOT_API_VERSION_INFO = _BotAPIVersion(major=6, minor=5)
|
||||
BOT_API_VERSION_INFO = _BotAPIVersion(major=6, minor=7)
|
||||
#: :obj:`str`: Telegram Bot API
|
||||
#: version supported by this version of `python-telegram-bot`. Also available as
|
||||
#: :data:`telegram.__bot_api_version__`.
|
||||
@@ -184,6 +189,43 @@ class BotCommandScopeType(StringEnum):
|
||||
""":obj:`str`: The type of :class:`telegram.BotCommandScopeChatMember`."""
|
||||
|
||||
|
||||
class BotDescriptionLimit(IntEnum):
|
||||
"""This enum contains limitations for the methods :meth:`telegram.Bot.set_my_description` and
|
||||
:meth:`telegram.Bot.set_my_short_description`. The enum members of this enumeration are
|
||||
instances of :class:`int` and can be treated as such.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
MAX_DESCRIPTION_LENGTH = 512
|
||||
""":obj:`int`: Maximum length for the parameter
|
||||
:paramref:`~telegram.Bot.set_my_description.description` of
|
||||
:meth:`telegram.Bot.set_my_description`
|
||||
"""
|
||||
MAX_SHORT_DESCRIPTION_LENGTH = 120
|
||||
""":obj:`int`: Maximum length for the parameter
|
||||
:paramref:`~telegram.Bot.set_my_short_description.short_description` of
|
||||
:meth:`telegram.Bot.set_my_short_description`
|
||||
"""
|
||||
|
||||
|
||||
class BotNameLimit(IntEnum):
|
||||
"""This enum contains limitations for the methods :meth:`telegram.Bot.set_my_name`.
|
||||
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
MAX_NAME_LENGTH = 64
|
||||
""":obj:`int`: Maximum length for the parameter :paramref:`~telegram.Bot.set_my_name.name` of
|
||||
:meth:`telegram.Bot.set_my_name`
|
||||
"""
|
||||
|
||||
|
||||
class CallbackQueryLimit(IntEnum):
|
||||
"""This enum contains limitations for :class:`telegram.CallbackQuery`/
|
||||
:meth:`telegram.Bot.answer_callback_query`. The enum members of this enumeration are instances
|
||||
@@ -710,11 +752,19 @@ class InlineQueryLimit(IntEnum):
|
||||
MIN_SWITCH_PM_TEXT_LENGTH = 1
|
||||
""":obj:`int`: Minimum number of characters in a :obj:`str` passed as the
|
||||
:paramref:`~telegram.Bot.answer_inline_query.switch_pm_parameter` parameter of
|
||||
:meth:`telegram.Bot.answer_inline_query`."""
|
||||
:meth:`telegram.Bot.answer_inline_query`.
|
||||
|
||||
.. deprecated:: 20.3
|
||||
Deprecated in favor of :attr:`InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH`.
|
||||
"""
|
||||
MAX_SWITCH_PM_TEXT_LENGTH = 64
|
||||
""":obj:`int`: Maximum number of characters in a :obj:`str` passed as the
|
||||
:paramref:`~telegram.Bot.answer_inline_query.switch_pm_parameter` parameter of
|
||||
:meth:`telegram.Bot.answer_inline_query`."""
|
||||
:meth:`telegram.Bot.answer_inline_query`.
|
||||
|
||||
.. deprecated:: 20.3
|
||||
Deprecated in favor of :attr:`InlineQueryResultsButtonLimit.MAX_START_PARAMETER_LENGTH`.
|
||||
"""
|
||||
|
||||
|
||||
class InlineQueryResultLimit(IntEnum):
|
||||
@@ -738,6 +788,26 @@ class InlineQueryResultLimit(IntEnum):
|
||||
"""
|
||||
|
||||
|
||||
class InlineQueryResultsButtonLimit(IntEnum):
|
||||
"""This enum contains limitations for :class:`telegram.InlineQueryResultsButton`.
|
||||
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
MIN_START_PARAMETER_LENGTH = InlineQueryLimit.MIN_SWITCH_PM_TEXT_LENGTH
|
||||
""":obj:`int`: Minimum number of characters in a :obj:`str` passed as the
|
||||
:paramref:`~telegram.InlineQueryResultsButton.start_parameter` parameter of
|
||||
:meth:`telegram.InlineQueryResultsButton`."""
|
||||
|
||||
MAX_START_PARAMETER_LENGTH = InlineQueryLimit.MAX_SWITCH_PM_TEXT_LENGTH
|
||||
""":obj:`int`: Maximum number of characters in a :obj:`str` passed as the
|
||||
:paramref:`~telegram.InlineQueryResultsButton.start_parameter` parameter of
|
||||
:meth:`telegram.InlineQueryResultsButton`."""
|
||||
|
||||
|
||||
class InlineQueryResultType(StringEnum):
|
||||
"""This enum contains the available types of :class:`telegram.InlineQueryResult`. The enum
|
||||
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||
@@ -1243,8 +1313,26 @@ class ReplyLimit(IntEnum):
|
||||
"""
|
||||
|
||||
|
||||
class StickerFormat(StringEnum):
|
||||
"""This enum contains the available formats of :class:`telegram.Sticker` in the set. The enum
|
||||
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
STATIC = "static"
|
||||
""":obj:`str`: Static sticker."""
|
||||
ANIMATED = "animated"
|
||||
""":obj:`str`: Animated sticker."""
|
||||
VIDEO = "video"
|
||||
""":obj:`str`: Video sticker."""
|
||||
|
||||
|
||||
class StickerLimit(IntEnum):
|
||||
"""This enum contains limitations for :meth:`telegram.Bot.create_new_sticker_set`.
|
||||
"""This enum contains limitations for various sticker methods, such as
|
||||
:meth:`telegram.Bot.create_new_sticker_set`.
|
||||
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
@@ -1264,6 +1352,78 @@ class StickerLimit(IntEnum):
|
||||
:paramref:`~telegram.Bot.create_new_sticker_set.title` parameter of
|
||||
:meth:`telegram.Bot.create_new_sticker_set`.
|
||||
"""
|
||||
MIN_STICKER_EMOJI = 1
|
||||
""":obj:`int`: Minimum number of emojis associated with a sticker, passed as the
|
||||
:paramref:`~telegram.Bot.setStickerEmojiList.emoji_list` parameter of
|
||||
:meth:`telegram.Bot.set_sticker_emoji_list`.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
MAX_STICKER_EMOJI = 20
|
||||
""":obj:`int`: Maximum number of emojis associated with a sticker, passed as the
|
||||
:paramref:`~telegram.Bot.setStickerEmojiList.emoji_list` parameter of
|
||||
:meth:`telegram.Bot.set_sticker_emoji_list`.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
MAX_SEARCH_KEYWORDS = 20
|
||||
""":obj:`int`: Maximum number of search keywords for a sticker, passed as the
|
||||
:paramref:`~telegram.Bot.set_sticker_keywords.keywords` parameter of
|
||||
:meth:`telegram.Bot.set_sticker_keywords`.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
MAX_KEYWORD_LENGTH = 64
|
||||
""":obj:`int`: Maximum number of characters in a search keyword for a sticker, for each item in
|
||||
:paramref:`~telegram.Bot.set_sticker_keywords.keywords` sequence of
|
||||
:meth:`telegram.Bot.set_sticker_keywords`.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
|
||||
|
||||
class StickerSetLimit(IntEnum):
|
||||
"""This enum contains limitations for various sticker set methods, such as
|
||||
:meth:`telegram.Bot.create_new_sticker_set` and :meth:`telegram.Bot.add_sticker_to_set`.
|
||||
|
||||
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
MIN_INITIAL_STICKERS = 1
|
||||
""":obj:`int`: Minimum number of stickers needed to create a sticker set, passed as the
|
||||
:paramref:`~telegram.Bot.create_new_sticker_set.stickers` parameter of
|
||||
:meth:`telegram.Bot.create_new_sticker_set`.
|
||||
"""
|
||||
MAX_INITIAL_STICKERS = 50
|
||||
""":obj:`int`: Maximum number of stickers allowed while creating a sticker set, passed as the
|
||||
:paramref:`~telegram.Bot.create_new_sticker_set.stickers` parameter of
|
||||
:meth:`telegram.Bot.create_new_sticker_set`.
|
||||
"""
|
||||
MAX_EMOJI_STICKERS = 200
|
||||
""":obj:`int`: Maximum number of stickers allowed in an emoji sticker set, as given in
|
||||
:meth:`telegram.Bot.add_sticker_to_set`.
|
||||
"""
|
||||
MAX_ANIMATED_STICKERS = 50
|
||||
""":obj:`int`: Maximum number of stickers allowed in an animated or video sticker set, as given
|
||||
in :meth:`telegram.Bot.add_sticker_to_set`.
|
||||
"""
|
||||
MAX_STATIC_STICKERS = 120
|
||||
""":obj:`int`: Maximum number of stickers allowed in a static sticker set, as given in
|
||||
:meth:`telegram.Bot.add_sticker_to_set`.
|
||||
"""
|
||||
MAX_STATIC_THUMBNAIL_SIZE = 128
|
||||
""":obj:`int`: Maximum size of the thumbnail if it is a **.WEBP** or **.PNG** in kilobytes,
|
||||
as given in :meth:`telegram.Bot.set_sticker_set_thumbnail`."""
|
||||
MAX_ANIMATED_THUMBNAIL_SIZE = 32
|
||||
""":obj:`int`: Maximum size of the thumbnail if it is a **.TGS** or **.WEBM** in kilobytes,
|
||||
as given in :meth:`telegram.Bot.set_sticker_set_thumbnail`."""
|
||||
STATIC_THUMB_DIMENSIONS = 100
|
||||
""":obj:`int`: Exact height and width of the thumbnail if it is a **.WEBP** or **.PNG** in
|
||||
pixels, as given in :meth:`telegram.Bot.set_sticker_set_thumbnail`."""
|
||||
|
||||
|
||||
class StickerType(StringEnum):
|
||||
|
||||
+7
-5
@@ -48,17 +48,19 @@ def _lstrip_str(in_s: str, lstr: str) -> str:
|
||||
:obj:`str`: The stripped string.
|
||||
|
||||
"""
|
||||
if in_s.startswith(lstr):
|
||||
res = in_s[len(lstr) :]
|
||||
else:
|
||||
res = in_s
|
||||
return res
|
||||
return in_s[len(lstr) :] if in_s.startswith(lstr) else in_s
|
||||
|
||||
|
||||
class TelegramError(Exception):
|
||||
"""
|
||||
Base class for Telegram errors.
|
||||
|
||||
Tip:
|
||||
Objects of this type can be serialized via Python's :mod:`pickle` module and pickled
|
||||
objects from one version of PTB are usually loadable in future versions. However, we can
|
||||
not guarantee that this compatibility will always be provided. At least a manual one-time
|
||||
conversion of the data may be needed on major updates of the library.
|
||||
|
||||
.. seealso:: :wiki:`Exceptions, Warnings and Logging <Exceptions%2C-Warnings-and-Logging>`
|
||||
"""
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ library.
|
||||
"""
|
||||
import asyncio
|
||||
import contextlib
|
||||
import logging
|
||||
import sys
|
||||
from typing import Any, AsyncIterator, Callable, Coroutine, Dict, List, Optional, Union
|
||||
|
||||
@@ -32,6 +31,7 @@ try:
|
||||
except ImportError:
|
||||
AIO_LIMITER_AVAILABLE = False
|
||||
|
||||
from telegram._utils.logging import get_logger
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram.error import RetryAfter
|
||||
from telegram.ext._baseratelimiter import BaseRateLimiter
|
||||
@@ -48,6 +48,9 @@ else:
|
||||
yield None
|
||||
|
||||
|
||||
_LOGGER = get_logger(__name__, class_name="AIORateLimiter")
|
||||
|
||||
|
||||
class AIORateLimiter(BaseRateLimiter[int]):
|
||||
"""
|
||||
Implementation of :class:`~telegram.ext.BaseRateLimiter` using the library
|
||||
@@ -118,7 +121,6 @@ class AIORateLimiter(BaseRateLimiter[int]):
|
||||
"_group_limiters",
|
||||
"_group_max_rate",
|
||||
"_group_time_period",
|
||||
"_logger",
|
||||
"_max_retries",
|
||||
"_retry_after_event",
|
||||
)
|
||||
@@ -152,7 +154,6 @@ class AIORateLimiter(BaseRateLimiter[int]):
|
||||
|
||||
self._group_limiters: Dict[Union[str, int], AsyncLimiter] = {}
|
||||
self._max_retries: int = max_retries
|
||||
self._logger = logging.getLogger(__name__)
|
||||
self._retry_after_event = asyncio.Event()
|
||||
self._retry_after_event.set()
|
||||
|
||||
@@ -203,7 +204,7 @@ class AIORateLimiter(BaseRateLimiter[int]):
|
||||
return await callback(*args, **kwargs)
|
||||
|
||||
# mypy doesn't understand that the last run of the for loop raises an exception
|
||||
async def process_request( # type: ignore[return]
|
||||
async def process_request(
|
||||
self,
|
||||
callback: Callable[..., Coroutine[Any, Any, Union[bool, JSONDict, List[JSONDict]]]],
|
||||
args: Any,
|
||||
@@ -232,10 +233,8 @@ class AIORateLimiter(BaseRateLimiter[int]):
|
||||
chat = True
|
||||
|
||||
# In case user passes integer chat id as string
|
||||
try:
|
||||
with contextlib.suppress(ValueError, TypeError):
|
||||
chat_id = int(chat_id)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if (isinstance(chat_id, int) and chat_id < 0) or isinstance(chat_id, str):
|
||||
# string chat_id only works for channels and supergroups
|
||||
@@ -249,16 +248,17 @@ class AIORateLimiter(BaseRateLimiter[int]):
|
||||
)
|
||||
except RetryAfter as exc:
|
||||
if i == max_retries:
|
||||
self._logger.exception(
|
||||
_LOGGER.exception(
|
||||
"Rate limit hit after maximum of %d retries", max_retries, exc_info=exc
|
||||
)
|
||||
raise exc
|
||||
|
||||
sleep = exc.retry_after + 0.1
|
||||
self._logger.info("Rate limit hit. Retrying after %f seconds", sleep)
|
||||
_LOGGER.info("Rate limit hit. Retrying after %f seconds", sleep)
|
||||
# Make sure we don't allow other requests to be processed
|
||||
self._retry_after_event.clear()
|
||||
await asyncio.sleep(sleep)
|
||||
finally:
|
||||
# Allow other requests to be processed
|
||||
self._retry_after_event.set()
|
||||
return None # type: ignore[return-value]
|
||||
|
||||
+113
-59
@@ -18,9 +18,9 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the Application class."""
|
||||
import asyncio
|
||||
import contextlib
|
||||
import inspect
|
||||
import itertools
|
||||
import logging
|
||||
import platform
|
||||
import signal
|
||||
from collections import defaultdict
|
||||
@@ -31,10 +31,12 @@ from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
AsyncContextManager,
|
||||
Awaitable,
|
||||
Callable,
|
||||
Coroutine,
|
||||
DefaultDict,
|
||||
Dict,
|
||||
Generator,
|
||||
Generic,
|
||||
List,
|
||||
Mapping,
|
||||
@@ -50,7 +52,8 @@ from typing import (
|
||||
|
||||
from telegram._update import Update
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE, DEFAULT_TRUE, DefaultValue
|
||||
from telegram._utils.types import DVType, ODVInput
|
||||
from telegram._utils.logging import get_logger
|
||||
from telegram._utils.types import SCT, DVType, ODVInput
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.error import TelegramError
|
||||
from telegram.ext._basepersistence import BasePersistence
|
||||
@@ -71,10 +74,10 @@ if TYPE_CHECKING:
|
||||
DEFAULT_GROUP: int = 0
|
||||
|
||||
_AppType = TypeVar("_AppType", bound="Application") # pylint: disable=invalid-name
|
||||
_RT = TypeVar("_RT")
|
||||
_STOP_SIGNAL = object()
|
||||
_DEFAULT_0 = DefaultValue(0)
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_LOGGER = get_logger(__name__)
|
||||
|
||||
|
||||
class ApplicationHandlerStop(Exception):
|
||||
@@ -136,7 +139,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
Examples:
|
||||
:any:`Echo Bot <examples.echobot>`
|
||||
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions-–-Your-first-Bot>`,
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions---Your-first-Bot>`,
|
||||
:wiki:`Architecture Overview <Architecture>`
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
@@ -390,7 +393,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
:meth:`shutdown`
|
||||
"""
|
||||
if self._initialized:
|
||||
_logger.debug("This Application is already initialized.")
|
||||
_LOGGER.debug("This Application is already initialized.")
|
||||
return
|
||||
|
||||
await self.bot.initialize()
|
||||
@@ -440,7 +443,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
raise RuntimeError("This Application is still running!")
|
||||
|
||||
if not self._initialized:
|
||||
_logger.debug("This Application is already shut down. Returning.")
|
||||
_LOGGER.debug("This Application is already shut down. Returning.")
|
||||
return
|
||||
|
||||
await self.bot.shutdown()
|
||||
@@ -448,10 +451,10 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
await self.updater.shutdown()
|
||||
|
||||
if self.persistence:
|
||||
_logger.debug("Updating & flushing persistence before shutdown")
|
||||
_LOGGER.debug("Updating & flushing persistence before shutdown")
|
||||
await self.update_persistence()
|
||||
await self.persistence.flush()
|
||||
_logger.debug("Updated and flushed persistence")
|
||||
_LOGGER.debug("Updated and flushed persistence")
|
||||
|
||||
self._initialized = False
|
||||
|
||||
@@ -554,18 +557,18 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
# TODO: Add this once we drop py3.7
|
||||
# name=f'Application:{self.bot.id}:persistence_updater'
|
||||
)
|
||||
_logger.debug("Loop for updating persistence started")
|
||||
_LOGGER.debug("Loop for updating persistence started")
|
||||
|
||||
if self._job_queue:
|
||||
await self._job_queue.start() # type: ignore[union-attr]
|
||||
_logger.debug("JobQueue started")
|
||||
_LOGGER.debug("JobQueue started")
|
||||
|
||||
self.__update_fetcher_task = asyncio.create_task(
|
||||
self._update_fetcher(),
|
||||
# TODO: Add this once we drop py3.7
|
||||
# name=f'Application:{self.bot.id}:update_fetcher'
|
||||
)
|
||||
_logger.info("Application started")
|
||||
_LOGGER.info("Application started")
|
||||
|
||||
except Exception as exc:
|
||||
self._running = False
|
||||
@@ -598,32 +601,32 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
raise RuntimeError("This Application is not running!")
|
||||
|
||||
self._running = False
|
||||
_logger.info("Application is stopping. This might take a moment.")
|
||||
_LOGGER.info("Application is stopping. This might take a moment.")
|
||||
|
||||
# Stop listening for new updates and handle all pending ones
|
||||
await self.update_queue.put(_STOP_SIGNAL)
|
||||
_logger.debug("Waiting for update_queue to join")
|
||||
_LOGGER.debug("Waiting for update_queue to join")
|
||||
await self.update_queue.join()
|
||||
if self.__update_fetcher_task:
|
||||
await self.__update_fetcher_task
|
||||
_logger.debug("Application stopped fetching of updates.")
|
||||
_LOGGER.debug("Application stopped fetching of updates.")
|
||||
|
||||
if self._job_queue:
|
||||
_logger.debug("Waiting for running jobs to finish")
|
||||
_LOGGER.debug("Waiting for running jobs to finish")
|
||||
await self._job_queue.stop(wait=True) # type: ignore[union-attr]
|
||||
_logger.debug("JobQueue stopped")
|
||||
_LOGGER.debug("JobQueue stopped")
|
||||
|
||||
_logger.debug("Waiting for `create_task` calls to be processed")
|
||||
_LOGGER.debug("Waiting for `create_task` calls to be processed")
|
||||
await asyncio.gather(*self.__create_task_tasks, return_exceptions=True)
|
||||
|
||||
# Make sure that this is the *last* step of stopping the application!
|
||||
if self.persistence and self.__update_persistence_task:
|
||||
_logger.debug("Waiting for persistence loop to finish")
|
||||
_LOGGER.debug("Waiting for persistence loop to finish")
|
||||
self.__update_persistence_event.set()
|
||||
await self.__update_persistence_task
|
||||
self.__update_persistence_event.clear()
|
||||
|
||||
_logger.info("Application.stop() complete")
|
||||
_LOGGER.info("Application.stop() complete")
|
||||
|
||||
def run_polling(
|
||||
self,
|
||||
@@ -934,7 +937,9 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
loop.close()
|
||||
|
||||
def create_task(
|
||||
self, coroutine: Coroutine[Any, Any, RT], update: object = None
|
||||
self,
|
||||
coroutine: Union[Generator[Optional["asyncio.Future[object]"], None, RT], Awaitable[RT]],
|
||||
update: object = None,
|
||||
) -> "asyncio.Task[RT]":
|
||||
"""Thin wrapper around :func:`asyncio.create_task` that handles exceptions raised by
|
||||
the :paramref:`coroutine` with :meth:`process_error`.
|
||||
@@ -948,7 +953,10 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
.. seealso:: :wiki:`Concurrency`
|
||||
|
||||
Args:
|
||||
coroutine (:term:`coroutine function`): The coroutine to run as task.
|
||||
coroutine (:term:`awaitable`): The awaitable to run as task.
|
||||
|
||||
.. versionchanged:: 20.2
|
||||
Accepts :class:`asyncio.Future` and generator-based coroutine functions.
|
||||
update (:obj:`object`, optional): If set, will be passed to :meth:`process_error`
|
||||
as additional information for the error handlers. Moreover, the corresponding
|
||||
:attr:`chat_data` and :attr:`user_data` entries will be updated in the next run of
|
||||
@@ -960,13 +968,16 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
return self.__create_task(coroutine=coroutine, update=update)
|
||||
|
||||
def __create_task(
|
||||
self, coroutine: Coroutine, update: object = None, is_error_handler: bool = False
|
||||
) -> asyncio.Task:
|
||||
self,
|
||||
coroutine: Union[Generator[Optional["asyncio.Future[object]"], None, RT], Awaitable[RT]],
|
||||
update: object = None,
|
||||
is_error_handler: bool = False,
|
||||
) -> "asyncio.Task[RT]":
|
||||
# Unfortunately, we can't know if `coroutine` runs one of the error handler functions
|
||||
# but by passing `is_error_handler=True` from `process_error`, we can make sure that we
|
||||
# get at most one recursion of the user calls `create_task` manually with an error handler
|
||||
# function
|
||||
task = asyncio.create_task(
|
||||
task: "asyncio.Task[RT]" = asyncio.create_task(
|
||||
self.__create_task_callback(
|
||||
coroutine=coroutine, update=update, is_error_handler=is_error_handler
|
||||
)
|
||||
@@ -988,18 +999,18 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
self.__create_task_tasks.discard(task) # Discard from our set since we are done with it
|
||||
# We just retrieve the eventual exception so that asyncio doesn't complain in case
|
||||
# it's not retrieved somewhere else
|
||||
try:
|
||||
with contextlib.suppress(asyncio.CancelledError, asyncio.InvalidStateError):
|
||||
task.exception()
|
||||
except (asyncio.CancelledError, asyncio.InvalidStateError):
|
||||
pass
|
||||
|
||||
async def __create_task_callback(
|
||||
self,
|
||||
coroutine: Coroutine[Any, Any, _RT],
|
||||
coroutine: Union[Generator[Optional["asyncio.Future[object]"], None, RT], Awaitable[RT]],
|
||||
update: object = None,
|
||||
is_error_handler: bool = False,
|
||||
) -> _RT:
|
||||
) -> RT:
|
||||
try:
|
||||
if isinstance(coroutine, Generator):
|
||||
return await asyncio.create_task(coroutine)
|
||||
return await coroutine
|
||||
except asyncio.CancelledError as cancel:
|
||||
# TODO: in py3.8+, CancelledError is a subclass of BaseException, so we can drop this
|
||||
@@ -1015,7 +1026,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
|
||||
# Avoid infinite recursion of error handlers.
|
||||
elif is_error_handler:
|
||||
_logger.exception(
|
||||
_LOGGER.exception(
|
||||
"An error was raised and an uncaught error was raised while "
|
||||
"handling the error with an error_handler.",
|
||||
exc_info=exception,
|
||||
@@ -1035,24 +1046,33 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
async def _update_fetcher(self) -> None:
|
||||
# Continuously fetch updates from the queue. Exit only once the signal object is found.
|
||||
while True:
|
||||
update = await self.update_queue.get()
|
||||
try:
|
||||
update = await self.update_queue.get()
|
||||
|
||||
if update is _STOP_SIGNAL:
|
||||
_logger.debug("Dropping pending updates")
|
||||
while not self.update_queue.empty():
|
||||
if update is _STOP_SIGNAL:
|
||||
_LOGGER.debug("Dropping pending updates")
|
||||
while not self.update_queue.empty():
|
||||
self.update_queue.task_done()
|
||||
|
||||
# For the _STOP_SIGNAL
|
||||
self.update_queue.task_done()
|
||||
return
|
||||
|
||||
# For the _STOP_SIGNAL
|
||||
self.update_queue.task_done()
|
||||
return
|
||||
_LOGGER.debug("Processing update %s", update)
|
||||
|
||||
_logger.debug("Processing update %s", update)
|
||||
|
||||
if self._concurrent_updates:
|
||||
# We don't await the below because it has to be run concurrently
|
||||
self.create_task(self.__process_update_wrapper(update), update=update)
|
||||
else:
|
||||
await self.__process_update_wrapper(update)
|
||||
if self._concurrent_updates:
|
||||
# We don't await the below because it has to be run concurrently
|
||||
self.create_task(self.__process_update_wrapper(update), update=update)
|
||||
else:
|
||||
await self.__process_update_wrapper(update)
|
||||
except asyncio.CancelledError:
|
||||
# This may happen if the application is manually run via application.start() and
|
||||
# then a KeyboardInterrupt is sent. We must prevent this loop to die since
|
||||
# application.stop() will wait for it's clean shutdown.
|
||||
_LOGGER.warning(
|
||||
"Fetching updates got a asyncio.CancelledError. Ignoring as this task may only"
|
||||
"be closed via `Application.stop`."
|
||||
)
|
||||
|
||||
async def __process_update_wrapper(self, update: object) -> None:
|
||||
async with self._concurrent_updates_sem:
|
||||
@@ -1106,13 +1126,13 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
|
||||
# Stop processing with any other handler.
|
||||
except ApplicationHandlerStop:
|
||||
_logger.debug("Stopping further handlers due to ApplicationHandlerStop")
|
||||
_LOGGER.debug("Stopping further handlers due to ApplicationHandlerStop")
|
||||
break
|
||||
|
||||
# Dispatch any error.
|
||||
except Exception as exc:
|
||||
if await self.process_error(update=update, error=exc):
|
||||
_logger.debug("Error handler stopped further handlers.")
|
||||
_LOGGER.debug("Error handler stopped further handlers.")
|
||||
break
|
||||
|
||||
if any_blocking:
|
||||
@@ -1189,7 +1209,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
Union[List[BaseHandler[Any, CCT]], Tuple[BaseHandler[Any, CCT]]],
|
||||
Dict[int, Union[List[BaseHandler[Any, CCT]], Tuple[BaseHandler[Any, CCT]]]],
|
||||
],
|
||||
group: Union[int, DefaultValue[int]] = DefaultValue(0),
|
||||
group: Union[int, DefaultValue[int]] = _DEFAULT_0,
|
||||
) -> None:
|
||||
"""Registers multiple handlers at once. The order of the handlers in the passed
|
||||
sequence(s) matters. See :meth:`add_handler` for details.
|
||||
@@ -1362,6 +1382,36 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
if job.user_id:
|
||||
self._user_ids_to_be_updated_in_persistence.add(job.user_id)
|
||||
|
||||
def mark_data_for_update_persistence(
|
||||
self, chat_ids: SCT[int] = None, user_ids: SCT[int] = None
|
||||
) -> None:
|
||||
"""Mark entries of :attr:`chat_data` and :attr:`user_data` to be updated on the next
|
||||
run of :meth:`update_persistence`.
|
||||
|
||||
Tip:
|
||||
Use this method sparingly. If you have to use this method, it likely means that you
|
||||
access and modify ``context.application.chat/user_data[some_id]`` within a callback.
|
||||
Note that for data which should be available globally in all handler callbacks
|
||||
independent of the chat/user, it is recommended to use :attr:`bot_data` instead.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
|
||||
Args:
|
||||
chat_ids (:obj:`int` | Collection[:obj:`int`], optional): Chat IDs to mark.
|
||||
user_ids (:obj:`int` | Collection[:obj:`int`], optional): User IDs to mark.
|
||||
|
||||
"""
|
||||
if chat_ids:
|
||||
if isinstance(chat_ids, int):
|
||||
self._chat_ids_to_be_updated_in_persistence.add(chat_ids)
|
||||
else:
|
||||
self._chat_ids_to_be_updated_in_persistence.update(chat_ids)
|
||||
if user_ids:
|
||||
if isinstance(user_ids, int):
|
||||
self._user_ids_to_be_updated_in_persistence.add(user_ids)
|
||||
else:
|
||||
self._user_ids_to_be_updated_in_persistence.update(user_ids)
|
||||
|
||||
async def _persistence_updater(self) -> None:
|
||||
# Update the persistence in regular intervals. Exit only when the stop event has been set
|
||||
while not self.__update_persistence_event.is_set():
|
||||
@@ -1388,8 +1438,9 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
along with :attr:`~telegram.ext.ExtBot.callback_data_cache` and the conversation states of
|
||||
any persistent :class:`~telegram.ext.ConversationHandler` registered for this application.
|
||||
|
||||
For :attr:`user_data`, :attr:`chat_data`, only entries used since the last run of this
|
||||
method are updated.
|
||||
For :attr:`user_data` and :attr:`chat_data`, only those entries are updated which either
|
||||
were used or have been manually marked via :meth:`mark_data_for_update_persistence` since
|
||||
the last run of this method.
|
||||
|
||||
Tip:
|
||||
This method will be called in regular intervals by the application. There is usually
|
||||
@@ -1399,7 +1450,8 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
Any data is deep copied with :func:`copy.deepcopy` before handing it over to the
|
||||
persistence in order to avoid race conditions, so all persisted data must be copyable.
|
||||
|
||||
.. seealso:: :attr:`telegram.ext.BasePersistence.update_interval`.
|
||||
.. seealso:: :attr:`telegram.ext.BasePersistence.update_interval`,
|
||||
:meth:`mark_data_for_update_persistence`
|
||||
"""
|
||||
async with self.__update_persistence_lock:
|
||||
await self.__update_persistence()
|
||||
@@ -1408,7 +1460,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
if not self.persistence:
|
||||
return
|
||||
|
||||
_logger.debug("Starting next run of updating the persistence.")
|
||||
_LOGGER.debug("Starting next run of updating the persistence.")
|
||||
|
||||
coroutines: Set[Coroutine] = set()
|
||||
|
||||
@@ -1476,13 +1528,13 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
# *all* tasks will be done.
|
||||
if not new_state.done():
|
||||
if self.running:
|
||||
_logger.debug(
|
||||
_LOGGER.debug(
|
||||
"A ConversationHandlers state was not yet resolved. Updating the "
|
||||
"persistence with the current state. Will check again on next run of "
|
||||
"Application.update_persistence."
|
||||
)
|
||||
else:
|
||||
_logger.warning(
|
||||
_LOGGER.warning(
|
||||
"A ConversationHandlers state was not yet resolved. Updating the "
|
||||
"persistence with the current state."
|
||||
)
|
||||
@@ -1502,7 +1554,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
)
|
||||
|
||||
results = await asyncio.gather(*coroutines, return_exceptions=True)
|
||||
_logger.debug("Finished updating persistence.")
|
||||
_LOGGER.debug("Finished updating persistence.")
|
||||
|
||||
# dispatch any errors
|
||||
await asyncio.gather(
|
||||
@@ -1543,7 +1595,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
:meth:`process_error`. Defaults to :obj:`True`.
|
||||
"""
|
||||
if callback in self.error_handlers:
|
||||
_logger.warning("The callback is already registered as an error handler. Ignoring.")
|
||||
_LOGGER.warning("The callback is already registered as an error handler. Ignoring.")
|
||||
return
|
||||
|
||||
self.error_handlers[callback] = block
|
||||
@@ -1562,7 +1614,9 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
update: Optional[object],
|
||||
error: Exception,
|
||||
job: "Job[CCT]" = None,
|
||||
coroutine: Coroutine[Any, Any, Any] = None,
|
||||
coroutine: Union[
|
||||
Generator[Optional["asyncio.Future[object]"], None, RT], Awaitable[RT]
|
||||
] = None,
|
||||
) -> bool:
|
||||
"""Processes an error by passing it to all error handlers registered with
|
||||
:meth:`add_error_handler`. If one of the error handlers raises
|
||||
@@ -1618,12 +1672,12 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
except ApplicationHandlerStop:
|
||||
return True
|
||||
except Exception as exc:
|
||||
_logger.exception(
|
||||
_LOGGER.exception(
|
||||
"An error was raised and an uncaught error was raised while "
|
||||
"handling the error with an error_handler.",
|
||||
exc_info=exc,
|
||||
)
|
||||
return False
|
||||
|
||||
_logger.exception("No error handlers are registered, logging exception.", exc_info=error)
|
||||
_LOGGER.exception("No error handlers are registered, logging exception.", exc_info=error)
|
||||
return False
|
||||
|
||||
@@ -114,7 +114,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
* Unless a custom :class:`telegram.Bot` instance is set via :meth:`bot`, :meth:`build` will
|
||||
use :class:`telegram.ext.ExtBot` for the bot.
|
||||
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions-–-Your-first-Bot>`,
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions---Your-first-Bot>`,
|
||||
:wiki:`Builder Pattern <Builder-Pattern>`
|
||||
|
||||
.. _`builder pattern`: https://en.wikipedia.org/wiki/Builder_pattern
|
||||
@@ -178,7 +178,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
self._get_updates_write_timeout: ODVInput[float] = DEFAULT_NONE
|
||||
self._get_updates_pool_timeout: ODVInput[float] = DEFAULT_NONE
|
||||
self._get_updates_request: DVInput["BaseRequest"] = DEFAULT_NONE
|
||||
self._get_updates_http_version: DVInput[str] = DefaultValue("2")
|
||||
self._get_updates_http_version: DVInput[str] = DefaultValue("1.1")
|
||||
self._private_key: ODVInput[bytes] = DEFAULT_NONE
|
||||
self._private_key_password: ODVInput[bytes] = DEFAULT_NONE
|
||||
self._defaults: ODVInput["Defaults"] = DEFAULT_NONE
|
||||
@@ -204,7 +204,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
self._post_shutdown: Optional[Callable[[Application], Coroutine[Any, Any, None]]] = None
|
||||
self._post_stop: Optional[Callable[[Application], Coroutine[Any, Any, None]]] = None
|
||||
self._rate_limiter: ODVInput["BaseRateLimiter"] = DEFAULT_NONE
|
||||
self._http_version: DVInput[str] = DefaultValue("2")
|
||||
self._http_version: DVInput[str] = DefaultValue("1.1")
|
||||
|
||||
def _build_request(self, get_updates: bool) -> BaseRequest:
|
||||
prefix = "_get_updates_" if get_updates else "_"
|
||||
@@ -232,7 +232,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
key: value for key, value in timeouts.items() if not isinstance(value, DefaultValue)
|
||||
}
|
||||
|
||||
http_version = DefaultValue.get_value(getattr(self, f"{prefix}http_version")) or "2"
|
||||
http_version = DefaultValue.get_value(getattr(self, f"{prefix}http_version")) or "1.1"
|
||||
|
||||
return HTTPXRequest(
|
||||
connection_pool_size=connection_pool_size,
|
||||
@@ -564,15 +564,33 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
def http_version(self: BuilderType, http_version: str) -> BuilderType:
|
||||
"""Sets the HTTP protocol version which is used for the
|
||||
:paramref:`~telegram.request.HTTPXRequest.http_version` parameter of
|
||||
:attr:`telegram.Bot.request`. By default, HTTP/2 is used.
|
||||
:attr:`telegram.Bot.request`. By default, HTTP/1.1 is used.
|
||||
|
||||
.. seealso:: :meth:`get_updates_http_version`
|
||||
|
||||
Note:
|
||||
Users have observed stability issues with HTTP/2, which happen due to how the `h2
|
||||
library handles <https://github.com/python-hyper/h2/issues/1181>`_ cancellations of
|
||||
keepalive connections. See `#3556 <https://github.com/python-telegram-bot/
|
||||
python-telegram-bot/issues/3556>`_ for a discussion.
|
||||
|
||||
If you want to use HTTP/2, you must install PTB with the optional requirement
|
||||
``http2``, i.e.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install python-telegram-bot[http2]
|
||||
|
||||
Keep in mind that the HTTP/1.1 implementation may be considered the `"more
|
||||
robust option at this time" <https://www.python-httpx.org/http2#enabling-http2>`_.
|
||||
|
||||
.. versionadded:: 20.1
|
||||
.. versionchanged:: 20.2
|
||||
Reset the default version to 1.1.
|
||||
|
||||
Args:
|
||||
http_version (:obj:`str`): Pass ``"1.1"`` if you'd like to use HTTP/1.1 for making
|
||||
requests to Telegram. Defaults to ``"2"``, in which case HTTP/2 is used.
|
||||
http_version (:obj:`str`): Pass ``"2"`` if you'd like to use HTTP/2 for making
|
||||
requests to Telegram. Defaults to ``"1.1"``, in which case HTTP/1.1 is used.
|
||||
|
||||
Returns:
|
||||
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
||||
@@ -705,15 +723,31 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
def get_updates_http_version(self: BuilderType, get_updates_http_version: str) -> BuilderType:
|
||||
"""Sets the HTTP protocol version which is used for the
|
||||
:paramref:`~telegram.request.HTTPXRequest.http_version` parameter which is used in the
|
||||
:meth:`telegram.Bot.get_updates` request. By default, HTTP/2 is used.
|
||||
:meth:`telegram.Bot.get_updates` request. By default, HTTP/1.1 is used.
|
||||
|
||||
.. seealso:: :meth:`http_version`
|
||||
|
||||
Note:
|
||||
Users have observed stability issues with HTTP/2, which happen due to how the `h2
|
||||
library handles <https://github.com/python-hyper/h2/issues/1181>`_ cancellations of
|
||||
keepalive connections. See `#3556 <https://github.com/python-telegram-bot/
|
||||
python-telegram-bot/issues/3556>`_ for a discussion.
|
||||
|
||||
You will also need to install the http2 dependency. Keep in mind that the HTTP/1.1
|
||||
implementation may be considered the `"more robust option at this time"
|
||||
<https://www.python-httpx.org/http2#enabling-http2>`_.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install httpx[http2]
|
||||
|
||||
.. versionadded:: 20.1
|
||||
.. versionchanged:: 20.2
|
||||
Reset the default version to 1.1.
|
||||
|
||||
Args:
|
||||
get_updates_http_version (:obj:`str`): Pass ``"1.1"`` if you'd like to use HTTP/1.1 for
|
||||
making requests to Telegram. Defaults to ``"2"``, in which case HTTP/2 is used.
|
||||
get_updates_http_version (:obj:`str`): Pass ``"2"`` if you'd like to use HTTP/2 for
|
||||
making requests to Telegram. Defaults to ``"1.1"``, in which case HTTP/1.1 is used.
|
||||
|
||||
Returns:
|
||||
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
||||
|
||||
@@ -357,6 +357,11 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
|
||||
:attr:`~telegram.ext.Application.user_data` to a callback. Can be used to update data
|
||||
stored in :attr:`~telegram.ext.Application.user_data` from an external source.
|
||||
|
||||
Warning:
|
||||
When using :meth:`~telegram.ext.ApplicationBuilder.concurrent_updates`, this method
|
||||
may be called while a handler callback is still running. This might lead to race
|
||||
conditions.
|
||||
|
||||
.. versionadded:: 13.6
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
@@ -375,6 +380,11 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
|
||||
:attr:`~telegram.ext.Application.chat_data` to a callback. Can be used to update data
|
||||
stored in :attr:`~telegram.ext.Application.chat_data` from an external source.
|
||||
|
||||
Warning:
|
||||
When using :meth:`~telegram.ext.ApplicationBuilder.concurrent_updates`, this method
|
||||
may be called while a handler callback is still running. This might lead to race
|
||||
conditions.
|
||||
|
||||
.. versionadded:: 13.6
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
@@ -393,6 +403,11 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
|
||||
:attr:`~telegram.ext.Application.bot_data` to a callback. Can be used to update data stored
|
||||
in :attr:`~telegram.ext.Application.bot_data` from an external source.
|
||||
|
||||
Warning:
|
||||
When using :meth:`~telegram.ext.ApplicationBuilder.concurrent_updates`, this method
|
||||
may be called while a handler callback is still running. This might lead to race
|
||||
conditions.
|
||||
|
||||
.. versionadded:: 13.6
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
||||
@@ -20,14 +20,16 @@
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Coroutine,
|
||||
Awaitable,
|
||||
Dict,
|
||||
Generator,
|
||||
Generic,
|
||||
List,
|
||||
Match,
|
||||
NoReturn,
|
||||
Optional,
|
||||
Type,
|
||||
Union,
|
||||
)
|
||||
|
||||
from telegram._callbackquery import CallbackQuery
|
||||
@@ -37,9 +39,9 @@ from telegram.ext._extbot import ExtBot
|
||||
from telegram.ext._utils.types import BD, BT, CD, UD
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from asyncio import Queue
|
||||
from asyncio import Future, Queue
|
||||
|
||||
from telegram.ext import Application, Job, JobQueue # noqa: F401
|
||||
from telegram.ext import Application, Job, JobQueue
|
||||
from telegram.ext._utils.types import CCT
|
||||
|
||||
_STORING_DATA_WIKI = (
|
||||
@@ -96,8 +98,8 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
|
||||
|
||||
.. versionadded:: 20.0
|
||||
Attributes:
|
||||
coroutine (:term:`coroutine function`): Optional. Only present in error handlers if the
|
||||
error was caused by a coroutine run with :meth:`Application.create_task` or a handler
|
||||
coroutine (:term:`awaitable`): Optional. Only present in error handlers if the
|
||||
error was caused by an awaitable run with :meth:`Application.create_task` or a handler
|
||||
callback with :attr:`block=False <BaseHandler.block>`.
|
||||
matches (List[:meth:`re.Match <re.Match.expand>`]): Optional. If the associated update
|
||||
originated from a :class:`filters.Regex`, this will contain a list of match objects for
|
||||
@@ -143,7 +145,9 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
|
||||
self.matches: Optional[List[Match[str]]] = None
|
||||
self.error: Optional[Exception] = None
|
||||
self.job: Optional["Job[CCT]"] = None
|
||||
self.coroutine: Optional[Coroutine[Any, Any, Any]] = None
|
||||
self.coroutine: Optional[
|
||||
Union[Generator[Optional["Future[object]"], None, Any], Awaitable[Any]]
|
||||
] = None
|
||||
|
||||
@property
|
||||
def application(self) -> "Application[BT, CCT, UD, CD, BD, Any]":
|
||||
@@ -275,7 +279,7 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
|
||||
error: Exception,
|
||||
application: "Application[BT, CCT, UD, CD, BD, Any]",
|
||||
job: "Job[Any]" = None,
|
||||
coroutine: Coroutine[Any, Any, Any] = None,
|
||||
coroutine: Union[Generator[Optional["Future[object]"], None, Any], Awaitable[Any]] = None,
|
||||
) -> "CCT":
|
||||
"""
|
||||
Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to the error
|
||||
@@ -295,13 +299,15 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
|
||||
job (:class:`telegram.ext.Job`, optional): The job associated with the error.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
coroutine (:term:`coroutine function`, optional): The coroutine function associated
|
||||
coroutine (:term:`awaitable`, optional): The awaitable associated
|
||||
with this error if the error was caused by a coroutine run with
|
||||
:meth:`Application.create_task` or a handler callback with
|
||||
:attr:`block=False <BaseHandler.block>`.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
|
||||
.. versionchanged:: 20.2
|
||||
Accepts :class:`asyncio.Future` and generator-based coroutine functions.
|
||||
Returns:
|
||||
:class:`telegram.ext.CallbackContext`
|
||||
"""
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
"""This module contains the ConversationHandler."""
|
||||
import asyncio
|
||||
import datetime
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
@@ -38,6 +37,7 @@ from typing import (
|
||||
|
||||
from telegram import Update
|
||||
from telegram._utils.defaultvalue import DEFAULT_TRUE, DefaultValue
|
||||
from telegram._utils.logging import get_logger
|
||||
from telegram._utils.types import DVType
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.ext._application import ApplicationHandlerStop
|
||||
@@ -56,7 +56,7 @@ if TYPE_CHECKING:
|
||||
from telegram.ext import Application, Job, JobQueue
|
||||
_CheckUpdateType = Tuple[object, ConversationKey, BaseHandler[Update, CCT], object]
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_LOGGER = get_logger(__name__, class_name="ConversationHandler")
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -102,7 +102,7 @@ class PendingState:
|
||||
|
||||
exc = self.task.exception()
|
||||
if exc:
|
||||
_logger.exception(
|
||||
_LOGGER.exception(
|
||||
"Task function raised exception. Falling back to old state %s",
|
||||
self.old_state,
|
||||
)
|
||||
@@ -259,7 +259,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
when :attr:`per_message`, :attr:`per_chat`, :attr:`per_user` are all :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
block (:obj:`bool`): Determines whether the callback will run in a blocking way.. Always
|
||||
block (:obj:`bool`): Determines whether the callback will run in a blocking way. Always
|
||||
:obj:`True` since conversation handlers handle any non-blocking callbacks internally.
|
||||
|
||||
"""
|
||||
@@ -649,12 +649,12 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
try:
|
||||
effective_new_state = await new_state
|
||||
except Exception as exc:
|
||||
_logger.debug(
|
||||
_LOGGER.debug(
|
||||
"Non-blocking handler callback raised exception. Not scheduling conversation "
|
||||
"timeout.",
|
||||
exc_info=exc,
|
||||
)
|
||||
return
|
||||
return None
|
||||
return self._schedule_job(
|
||||
new_state=effective_new_state,
|
||||
application=application,
|
||||
@@ -684,7 +684,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
data=_ConversationTimeoutContext(conversation_key, update, application, context),
|
||||
)
|
||||
except Exception as exc:
|
||||
_logger.exception("Failed to schedule timeout.", exc_info=exc)
|
||||
_LOGGER.exception("Failed to schedule timeout.", exc_info=exc)
|
||||
|
||||
# pylint: disable=too-many-return-statements
|
||||
def check_update(self, update: object) -> Optional[_CheckUpdateType[CCT]]:
|
||||
@@ -719,7 +719,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
|
||||
# Resolve futures
|
||||
if isinstance(state, PendingState):
|
||||
_logger.debug("Waiting for asyncio Task to finish ...")
|
||||
_LOGGER.debug("Waiting for asyncio Task to finish ...")
|
||||
|
||||
# check if future is finished or not
|
||||
if state.done():
|
||||
@@ -741,7 +741,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
return self.WAITING, key, handler_, check
|
||||
return None
|
||||
|
||||
_logger.debug("Selecting conversation %s with state %s", str(key), str(state))
|
||||
_LOGGER.debug("Selecting conversation %s with state %s", str(key), str(state))
|
||||
|
||||
handler: Optional[BaseHandler] = None
|
||||
|
||||
@@ -813,13 +813,12 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
# 3. Default values of the bot
|
||||
if handler.block is not DEFAULT_TRUE:
|
||||
block = handler.block
|
||||
elif self._block is not DEFAULT_TRUE:
|
||||
block = self._block
|
||||
elif isinstance(application.bot, ExtBot) and application.bot.defaults is not None:
|
||||
block = application.bot.defaults.block
|
||||
else:
|
||||
if self._block is not DEFAULT_TRUE:
|
||||
block = self._block
|
||||
elif isinstance(application.bot, ExtBot) and application.bot.defaults is not None:
|
||||
block = application.bot.defaults.block
|
||||
else:
|
||||
block = DefaultValue.get_value(handler.block)
|
||||
block = DefaultValue.get_value(handler.block)
|
||||
|
||||
try: # Now create task or await the callback
|
||||
if block:
|
||||
@@ -841,26 +840,25 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
if application.job_queue is None:
|
||||
warn(
|
||||
"Ignoring `conversation_timeout` because the Application has no JobQueue.",
|
||||
stacklevel=1,
|
||||
)
|
||||
elif not application.job_queue.scheduler.running:
|
||||
warn(
|
||||
"Ignoring `conversation_timeout` because the Applications JobQueue is "
|
||||
"not running.",
|
||||
stacklevel=1,
|
||||
)
|
||||
else:
|
||||
elif isinstance(new_state, asyncio.Task):
|
||||
# Add the new timeout job
|
||||
# checking if the new state is self.END is done in _schedule_job
|
||||
if isinstance(new_state, asyncio.Task):
|
||||
application.create_task(
|
||||
self._schedule_job_delayed(
|
||||
new_state, application, update, context, conversation_key
|
||||
),
|
||||
update=update,
|
||||
)
|
||||
else:
|
||||
self._schedule_job(
|
||||
application.create_task(
|
||||
self._schedule_job_delayed(
|
||||
new_state, application, update, context, conversation_key
|
||||
)
|
||||
),
|
||||
update=update,
|
||||
)
|
||||
else:
|
||||
self._schedule_job(new_state, application, update, context, conversation_key)
|
||||
|
||||
if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent:
|
||||
self._update_state(self.END, conversation_key, handler)
|
||||
@@ -874,7 +872,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
if raise_dp_handler_stop:
|
||||
# Don't pass the new state here. If we're in a nested conversation, the parent is
|
||||
# expecting None as return value.
|
||||
raise ApplicationHandlerStop()
|
||||
raise ApplicationHandlerStop
|
||||
# Signals a possible parent conversation to stay in the current state
|
||||
return None
|
||||
|
||||
@@ -909,7 +907,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
job = cast("Job", context.job)
|
||||
ctxt = cast(_ConversationTimeoutContext, job.data)
|
||||
|
||||
_logger.debug(
|
||||
_LOGGER.debug(
|
||||
"Conversation timeout was triggered for conversation %s!", ctxt.conversation_key
|
||||
)
|
||||
|
||||
@@ -935,6 +933,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
warn(
|
||||
"ApplicationHandlerStop in TIMEOUT state of "
|
||||
"ConversationHandler has no effect. Ignoring.",
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
self._update_state(self.END, ctxt.conversation_key)
|
||||
|
||||
@@ -468,12 +468,12 @@ class DictPersistence(BasePersistence[Dict[Any, Any], Dict[Any, Any], Dict[Any,
|
||||
tmp: Dict[int, Dict[object, object]] = {}
|
||||
decoded_data = json.loads(data)
|
||||
for user, user_data in decoded_data.items():
|
||||
user = int(user)
|
||||
tmp[user] = {}
|
||||
int_user_id = int(user)
|
||||
tmp[int_user_id] = {}
|
||||
for key, value in user_data.items():
|
||||
try:
|
||||
key = int(key)
|
||||
_id = int(key)
|
||||
except ValueError:
|
||||
pass
|
||||
tmp[user][key] = value
|
||||
_id = key
|
||||
tmp[int_user_id][_id] = value
|
||||
return tmp
|
||||
|
||||
+346
-8
@@ -30,6 +30,7 @@ from typing import (
|
||||
Optional,
|
||||
Sequence,
|
||||
Tuple,
|
||||
Type,
|
||||
TypeVar,
|
||||
Union,
|
||||
cast,
|
||||
@@ -44,6 +45,9 @@ from telegram import (
|
||||
Bot,
|
||||
BotCommand,
|
||||
BotCommandScope,
|
||||
BotDescription,
|
||||
BotName,
|
||||
BotShortDescription,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
ChatAdministratorRights,
|
||||
@@ -57,7 +61,9 @@ from telegram import (
|
||||
ForumTopic,
|
||||
GameHighScore,
|
||||
InlineKeyboardMarkup,
|
||||
InlineQueryResultsButton,
|
||||
InputMedia,
|
||||
InputSticker,
|
||||
Location,
|
||||
MaskPosition,
|
||||
MenuButton,
|
||||
@@ -81,10 +87,12 @@ from telegram import (
|
||||
)
|
||||
from telegram._utils.datetime import to_timestamp
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
|
||||
from telegram._utils.logging import get_logger
|
||||
from telegram._utils.types import DVInput, FileInput, JSONDict, ODVInput, ReplyMarkup
|
||||
from telegram.ext._callbackdatacache import CallbackDataCache
|
||||
from telegram.ext._utils.types import RLARGS
|
||||
from telegram.request import BaseRequest
|
||||
from telegram.warnings import PTBUserWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import (
|
||||
@@ -150,6 +158,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
__slots__ = ("_callback_data_cache", "_defaults", "_rate_limiter")
|
||||
|
||||
_LOGGER = get_logger(__name__, class_name="ExtBot")
|
||||
|
||||
# using object() would be a tiny bit safer, but a string plays better with the typing setup
|
||||
__RL_KEY = uuid4().hex
|
||||
|
||||
@@ -226,6 +236,15 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
self._callback_data_cache = CallbackDataCache(bot=self, maxsize=maxsize)
|
||||
|
||||
@classmethod
|
||||
def _warn(
|
||||
cls, message: str, category: Type[Warning] = PTBUserWarning, stacklevel: int = 0
|
||||
) -> None:
|
||||
"""We override this method to add one more level to the stacklevel, so that the warning
|
||||
points to the user's code, not to the PTB code.
|
||||
"""
|
||||
super()._warn(message=message, category=category, stacklevel=stacklevel + 2)
|
||||
|
||||
@property
|
||||
def callback_data_cache(self) -> Optional[CallbackDataCache]:
|
||||
""":class:`telegram.ext.CallbackDataCache`: Optional. The cache for
|
||||
@@ -318,7 +337,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
"connect_timeout": connect_timeout,
|
||||
"pool_timeout": pool_timeout,
|
||||
}
|
||||
self._logger.debug(
|
||||
self._LOGGER.debug(
|
||||
"Passing request through rate limiter of type %s with rate_limit_args %s",
|
||||
type(self.rate_limiter),
|
||||
rate_limit_args,
|
||||
@@ -379,10 +398,10 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
# 3)
|
||||
elif isinstance(val, InputMedia) and val.parse_mode is DEFAULT_NONE:
|
||||
# Copy object as not to edit it in-place
|
||||
val = copy(val)
|
||||
with val._unfrozen():
|
||||
val.parse_mode = self.defaults.parse_mode if self.defaults else None
|
||||
data[key] = val
|
||||
copied_val = copy(val)
|
||||
with copied_val._unfrozen():
|
||||
copied_val.parse_mode = self.defaults.parse_mode if self.defaults else None
|
||||
data[key] = copied_val
|
||||
elif key == "media" and isinstance(val, Sequence):
|
||||
# Copy objects as not to edit them in-place
|
||||
copy_list = [copy(media) for media in val]
|
||||
@@ -706,11 +725,12 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
name: str,
|
||||
emojis: str,
|
||||
emojis: str = None, # Was made optional for compatibility reasons
|
||||
png_sticker: FileInput = None,
|
||||
mask_position: MaskPosition = None,
|
||||
tgs_sticker: FileInput = None,
|
||||
webm_sticker: FileInput = None,
|
||||
sticker: InputSticker = None, # Actually a required param, but is optional for compat.
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
@@ -722,6 +742,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
return await super().add_sticker_to_set(
|
||||
user_id=user_id,
|
||||
name=name,
|
||||
sticker=sticker,
|
||||
emojis=emojis,
|
||||
png_sticker=png_sticker,
|
||||
mask_position=mask_position,
|
||||
@@ -773,6 +794,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
next_offset: str = None,
|
||||
switch_pm_text: str = None,
|
||||
switch_pm_parameter: str = None,
|
||||
button: InlineQueryResultsButton = None,
|
||||
*,
|
||||
current_offset: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -795,6 +817,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
button=button,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
@@ -1031,12 +1054,15 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
user_id: Union[str, int],
|
||||
name: str,
|
||||
title: str,
|
||||
emojis: str,
|
||||
emojis: str = None, # Was made optional for compatibility purposes
|
||||
png_sticker: FileInput = None,
|
||||
mask_position: MaskPosition = None,
|
||||
tgs_sticker: FileInput = None,
|
||||
webm_sticker: FileInput = None,
|
||||
sticker_type: str = None,
|
||||
stickers: Sequence[InputSticker] = None, # Actually a required param. Optional for compat.
|
||||
sticker_format: str = None, # Actually a required param. Optional for compat.
|
||||
needs_repainting: bool = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
@@ -1049,6 +1075,9 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
user_id=user_id,
|
||||
name=name,
|
||||
title=title,
|
||||
stickers=stickers,
|
||||
sticker_format=sticker_format,
|
||||
needs_repainting=needs_repainting,
|
||||
emojis=emojis,
|
||||
png_sticker=png_sticker,
|
||||
mask_position=mask_position,
|
||||
@@ -2150,6 +2179,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
has_spoiler: bool = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2176,6 +2206,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
filename=filename,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
@@ -2201,6 +2232,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
caption_entities: Sequence["MessageEntity"] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2226,6 +2258,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
caption_entities=caption_entities,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
filename=filename,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
@@ -2349,6 +2382,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
caption_entities: Sequence["MessageEntity"] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2372,6 +2406,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
caption_entities=caption_entities,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
filename=filename,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
@@ -2724,6 +2759,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
emoji: str = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
@@ -2745,6 +2781,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
emoji=emoji,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
@@ -2817,6 +2854,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
has_spoiler: bool = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2844,6 +2882,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
filename=filename,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
@@ -2865,6 +2904,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: int = None,
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
filename: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2886,6 +2926,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
filename=filename,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
@@ -3218,6 +3259,30 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def set_sticker_set_thumbnail(
|
||||
self,
|
||||
name: str,
|
||||
user_id: Union[str, int],
|
||||
thumbnail: FileInput = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> bool:
|
||||
return await super().set_sticker_set_thumbnail(
|
||||
name=name,
|
||||
user_id=user_id,
|
||||
thumbnail=thumbnail,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def set_sticker_set_thumb(
|
||||
self,
|
||||
name: str,
|
||||
@@ -3413,7 +3478,9 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
async def upload_sticker_file(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
png_sticker: FileInput,
|
||||
png_sticker: FileInput = None, # Deprecated since bot api 6.6. Optional for compatiblity.
|
||||
sticker: FileInput = None, # Actually required, but optional for compatibility.
|
||||
sticker_format: str = None, # Actually required, but optional for compatibility.
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
@@ -3424,6 +3491,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
) -> File:
|
||||
return await super().upload_sticker_file(
|
||||
user_id=user_id,
|
||||
sticker=sticker,
|
||||
sticker_format=sticker_format,
|
||||
png_sticker=png_sticker,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
@@ -3432,6 +3501,262 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def set_my_description(
|
||||
self,
|
||||
description: str = None,
|
||||
language_code: str = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> bool:
|
||||
return await super().set_my_description(
|
||||
description=description,
|
||||
language_code=language_code,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def set_my_short_description(
|
||||
self,
|
||||
short_description: str = None,
|
||||
language_code: str = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> bool:
|
||||
return await super().set_my_short_description(
|
||||
short_description=short_description,
|
||||
language_code=language_code,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def get_my_description(
|
||||
self,
|
||||
language_code: str = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> BotDescription:
|
||||
return await super().get_my_description(
|
||||
language_code=language_code,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def get_my_short_description(
|
||||
self,
|
||||
language_code: str = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> BotShortDescription:
|
||||
return await super().get_my_short_description(
|
||||
language_code=language_code,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def set_my_name(
|
||||
self,
|
||||
name: str = None,
|
||||
language_code: str = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> bool:
|
||||
return await super().set_my_name(
|
||||
name=name,
|
||||
language_code=language_code,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def get_my_name(
|
||||
self,
|
||||
language_code: str = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> BotName:
|
||||
return await super().get_my_name(
|
||||
language_code=language_code,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def set_custom_emoji_sticker_set_thumbnail(
|
||||
self,
|
||||
name: str,
|
||||
custom_emoji_id: str = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> bool:
|
||||
return await super().set_custom_emoji_sticker_set_thumbnail(
|
||||
name=name,
|
||||
custom_emoji_id=custom_emoji_id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def set_sticker_set_title(
|
||||
self,
|
||||
name: str,
|
||||
title: str,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> bool:
|
||||
return await super().set_sticker_set_title(
|
||||
name=name,
|
||||
title=title,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def delete_sticker_set(
|
||||
self,
|
||||
name: str,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> bool:
|
||||
return await super().delete_sticker_set(
|
||||
name=name,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def set_sticker_emoji_list(
|
||||
self,
|
||||
sticker: str,
|
||||
emoji_list: Sequence[str],
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> bool:
|
||||
return await super().set_sticker_emoji_list(
|
||||
sticker=sticker,
|
||||
emoji_list=emoji_list,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def set_sticker_keywords(
|
||||
self,
|
||||
sticker: str,
|
||||
keywords: Sequence[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> bool:
|
||||
return await super().set_sticker_keywords(
|
||||
sticker=sticker,
|
||||
keywords=keywords,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def set_sticker_mask_position(
|
||||
self,
|
||||
sticker: str,
|
||||
mask_position: MaskPosition = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> bool:
|
||||
return await super().set_sticker_mask_position(
|
||||
sticker=sticker,
|
||||
mask_position=mask_position,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
# updated camelCase aliases
|
||||
getMe = get_me
|
||||
sendMessage = send_message
|
||||
@@ -3507,6 +3832,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
setStickerPositionInSet = set_sticker_position_in_set
|
||||
deleteStickerFromSet = delete_sticker_from_set
|
||||
setStickerSetThumb = set_sticker_set_thumb
|
||||
setStickerSetThumbnail = set_sticker_set_thumbnail
|
||||
setPassportDataErrors = set_passport_data_errors
|
||||
sendPoll = send_poll
|
||||
stopPoll = stop_poll
|
||||
@@ -3533,3 +3859,15 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
reopenGeneralForumTopic = reopen_general_forum_topic
|
||||
hideGeneralForumTopic = hide_general_forum_topic
|
||||
unhideGeneralForumTopic = unhide_general_forum_topic
|
||||
setMyDescription = set_my_description
|
||||
getMyDescription = get_my_description
|
||||
setMyShortDescription = set_my_short_description
|
||||
getMyShortDescription = get_my_short_description
|
||||
setCustomEmojiStickerSetThumbnail = set_custom_emoji_sticker_set_thumbnail
|
||||
setStickerSetTitle = set_sticker_set_title
|
||||
deleteStickerSet = delete_sticker_set
|
||||
setStickerEmojiList = set_sticker_emoji_list
|
||||
setStickerKeywords = set_sticker_keywords
|
||||
setStickerMaskPosition = set_sticker_mask_position
|
||||
setMyName = set_my_name
|
||||
getMyName = get_my_name
|
||||
|
||||
@@ -41,6 +41,9 @@ if TYPE_CHECKING:
|
||||
from telegram.ext import Application
|
||||
|
||||
|
||||
_ALL_DAYS = tuple(range(7))
|
||||
|
||||
|
||||
class JobQueue(Generic[CCT]):
|
||||
"""This class allows you to periodically perform tasks with the bot. It is a convenience
|
||||
wrapper for the APScheduler library.
|
||||
@@ -288,6 +291,18 @@ class JobQueue(Generic[CCT]):
|
||||
:attr:`telegram.ext.Defaults.tzinfo` is used.
|
||||
|
||||
Defaults to :paramref:`interval`
|
||||
|
||||
Note:
|
||||
Setting :paramref:`first` to ``0``, ``datetime.datetime.now()`` or another
|
||||
value that indicates that the job should run immediately will not work due
|
||||
to how the APScheduler library works. If you want to run a job immediately,
|
||||
we recommend to use an approach along the lines of::
|
||||
|
||||
job = context.job_queue.run_repeating(callback, interval=5)
|
||||
await job.run(context.application)
|
||||
|
||||
.. seealso:: :meth:`telegram.ext.Job.run`
|
||||
|
||||
last (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \
|
||||
:obj:`datetime.datetime` | :obj:`datetime.time`, optional):
|
||||
Latest possible time for the job to run. This parameter will be interpreted
|
||||
@@ -436,7 +451,7 @@ class JobQueue(Generic[CCT]):
|
||||
self,
|
||||
callback: JobCallback[CCT],
|
||||
time: datetime.time,
|
||||
days: Tuple[int, ...] = tuple(range(7)),
|
||||
days: Tuple[int, ...] = _ALL_DAYS,
|
||||
data: object = None,
|
||||
name: str = None,
|
||||
chat_id: int = None,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user