mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-21 16:45:17 +00:00
Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 21ded420e2 | |||
| 7d893fd04b | |||
| 7015f8dedc | |||
| ac02bce109 | |||
| 3a9a0ab96d | |||
| aba17cb997 | |||
| 038a3b4452 | |||
| b03ebc5a65 | |||
| e9c01c7772 | |||
| 552298595c | |||
| 2a4a0d0ccd | |||
| eb993db473 | |||
| c77ef7eef3 | |||
| a34f0b9bee | |||
| eee8921598 | |||
| 1902c0ac36 | |||
| 544a3fbf48 | |||
| 36d49ea9cd | |||
| 25506f131d | |||
| 70aba136e4 | |||
| 40995b19fe | |||
| 32da6d6fce | |||
| f31787a8ef | |||
| b43a599e53 | |||
| 7a3fd83570 | |||
| 9ada2a7cca | |||
| be54cf4ece | |||
| 0c9915243d | |||
| 9930725e2a | |||
| ffd675daec | |||
| 6a831f926b | |||
| 6903d58142 | |||
| 07b6ee69d2 | |||
| c8a3c31dcc | |||
| 91e0271e4c | |||
| 9ddb361f76 | |||
| 89c522d883 | |||
| 2effff8254 | |||
| 2788191657 | |||
| aec6d3bada | |||
| 80b34811ab | |||
| 2d7a974b8f | |||
| ef703d19e9 | |||
| 77a8c64f6c | |||
| 786762bb73 | |||
| e0dbb99b08 |
+13
-14
@@ -50,6 +50,8 @@ Instructions for making a code change
|
||||
|
||||
The central development branch is ``master``, which should be clean and ready for release at any time. In general, all changes should be done as feature branches based off of ``master``.
|
||||
|
||||
If you want to do solely documentation changes, base them and PR to the branch ``doc-fixes``. This branch also has its own `RTD build`_.
|
||||
|
||||
Here's how to make a one-off code change.
|
||||
|
||||
1. **Choose a descriptive branch name.** It should be lowercase, hyphen-separated, and a noun describing the change (so, ``fuzzy-rules``, but not ``implement-fuzzy-rules``). Also, it shouldn't start with ``hotfix`` or ``release``.
|
||||
@@ -91,6 +93,8 @@ Here's how to make a one-off code change.
|
||||
|
||||
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.
|
||||
|
||||
- For consistency, please conform to `Google Python Style Guide`_ and `Google Python Style Docstrings`_.
|
||||
|
||||
- The following exceptions to the above (Google's) style guides applies:
|
||||
@@ -107,12 +111,6 @@ Here's how to make a one-off code change.
|
||||
|
||||
- Before making a commit ensure that all automated tests still pass:
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ make test
|
||||
|
||||
If you don't have ``make``, do:
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ pytest -v
|
||||
@@ -125,18 +123,18 @@ Here's how to make a one-off code change.
|
||||
|
||||
prior to running the tests.
|
||||
|
||||
- To actually make the commit (this will trigger tests for yapf, lint and pep8 automatically):
|
||||
- If you want run style & type checks before committing run
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ pre-commit run -a
|
||||
|
||||
- To actually make the commit (this will trigger tests style & type checks automatically):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ git add your-file-changed.py
|
||||
|
||||
- yapf may change code formatting, make sure to re-add them to your commit.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ git commit -a -m "your-commit-message-here"
|
||||
|
||||
- Finally, push it to your GitHub fork, run:
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -194,7 +192,7 @@ Style commandments
|
||||
Assert comparison order
|
||||
#######################
|
||||
|
||||
- assert statements should compare in **actual** == **expected** order.
|
||||
Assert statements should compare in **actual** == **expected** order.
|
||||
For example (assuming ``test_call`` is the thing being tested):
|
||||
|
||||
.. code-block:: python
|
||||
@@ -254,3 +252,4 @@ break the API classes. For example:
|
||||
.. _`here`: https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html
|
||||
.. _`Black`: https://black.readthedocs.io/en/stable/index.html
|
||||
.. _`popular editors`: https://black.readthedocs.io/en/stable/editor_integration.html
|
||||
.. _`RTD build`: https://python-telegram-bot.readthedocs.io/en/doc-fixes
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<!--
|
||||
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).
|
||||
-->
|
||||
|
||||
### 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
|
||||
- [ ] Added myself alphabetically to `AUTHORS.rst` (optional)
|
||||
|
||||
|
||||
### If the PR contains API changes (otherwise, you can delete this passage)
|
||||
|
||||
* New classes:
|
||||
- [ ] Added `self._id_attrs` and corresponding documentation
|
||||
- [ ] `__init__` accepts `**_kwargs`
|
||||
|
||||
* 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
|
||||
- [ ] Added new handlers for new update types
|
||||
- [ ] Added new filters for new message (sub)types
|
||||
- [ ] Added or updated documentation for the changed class(es) and/or method(s)
|
||||
- [ ] 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`
|
||||
@@ -0,0 +1,17 @@
|
||||
name: Warning maintainers
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- requirements.txt
|
||||
- requirements-dev.txt
|
||||
- .pre-commit-config.yaml
|
||||
jobs:
|
||||
job:
|
||||
runs-on: ubuntu-latest
|
||||
name: about pre-commit and dependency change
|
||||
steps:
|
||||
- name: running the check
|
||||
uses: Poolitzer/notifier-action@master
|
||||
with:
|
||||
notify-message: Hey! Looks like you edited the (dev) requirements or the pre-commit hooks. I'm just a friendly reminder to keep the pre-commit hook versions in sync with the dev requirements and the additional dependencies for the hooks in sync with the requirements :)
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,16 @@
|
||||
name: Warning maintainers
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- README.rst
|
||||
- README_RAW.rst
|
||||
jobs:
|
||||
job:
|
||||
runs-on: ubuntu-latest
|
||||
name: about readme change
|
||||
steps:
|
||||
- name: running the check
|
||||
uses: Poolitzer/notifier-action@master
|
||||
with:
|
||||
notify-message: Hey! Looks like you edited README.rst or README_RAW.rst. I'm just a friendly reminder to apply relevant changes to both of those files :)
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
+20
-17
@@ -3,8 +3,6 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
schedule:
|
||||
- cron: 7 3 * * *
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
@@ -16,14 +14,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.6, 3.7, 3.8, 3.9]
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
python-version: 3.7
|
||||
test-build: True
|
||||
- os: windows-latest
|
||||
python-version: 3.7
|
||||
test-build: True
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -42,18 +33,30 @@ jobs:
|
||||
python -W ignore -m pip install -r requirements-dev.txt
|
||||
|
||||
- name: Test with pytest
|
||||
# We run 3 different suites here
|
||||
# 1. Test just utils.helpers.py without pytz being installed
|
||||
# 2. Test just test_no_passport.py without passport dependencies being installed
|
||||
# 3. Test everything else
|
||||
# The first & second one are achieved by mocking the corresponding import
|
||||
# See test_helpers.py & test_no_passport.py for details
|
||||
run: |
|
||||
pytest -v -m nocoverage
|
||||
nocov_exit=$?
|
||||
pytest -v -m "not nocoverage" --cov
|
||||
cov_exit=$?
|
||||
global_exit=$(( nocov_exit > cov_exit ? nocov_exit : cov_exit ))
|
||||
pytest -v --cov -k test_no_passport.py
|
||||
no_passport_exit=$?
|
||||
export TEST_NO_PASSPORT='false'
|
||||
pytest -v --cov --cov-append -k test_helpers.py
|
||||
no_pytz_exit=$?
|
||||
export TEST_NO_PYTZ='false'
|
||||
pytest -v --cov --cov-append
|
||||
full_exit=$?
|
||||
special_exit=$(( no_pytz_exit > no_passport_exit ? no_pytz_exit : no_passport_exit ))
|
||||
global_exit=$(( special_exit > full_exit ? special_exit : full_exit ))
|
||||
exit ${global_exit}
|
||||
env:
|
||||
JOB_INDEX: ${{ strategy.job-index }}
|
||||
BOTS: W3sidG9rZW4iOiAiNjk2MTg4NzMyOkFBR1Z3RUtmSEhsTmpzY3hFRE5LQXdraEdzdFpfa28xbUMwIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WldGaU1UUmxNbVF5TnpNeSIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIENQeXRob24gMi43IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxMzkwOTgzOTk3IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19jcHl0aG9uXzI3X2JvdCJ9LCB7InRva2VuIjogIjY3MTQ2ODg4NjpBQUdQR2ZjaVJJQlVORmU4MjR1SVZkcTdKZTNfWW5BVE5HdyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpHWXdPVGxrTXpNeE4yWTIiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIFRyYXZpcyB1c2luZyBDUHl0aG9uIDMuNCIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTQ0NjAyMjUyMiIsICJib3RfdXNlcm5hbWUiOiAiQHB0Yl90cmF2aXNfY3B5dGhvbl8zNF9ib3QifSwgeyJ0b2tlbiI6ICI2MjkzMjY1Mzg6QUFGUnJaSnJCN29CM211ekdzR0pYVXZHRTVDUXpNNUNVNG8iLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpNbU01WVdKaFl6a3hNMlUxIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBvbiBUcmF2aXMgdXNpbmcgQ1B5dGhvbiAzLjUiLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDE0OTY5MTc3NTAiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfdHJhdmlzX2NweXRob25fMzVfYm90In0sIHsidG9rZW4iOiAiNjQwMjA4OTQzOkFBRmhCalFwOXFtM1JUeFN6VXBZekJRakNsZS1Kano1aGNrIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WXpoa1pUZzFOamMxWXpWbCIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIENQeXRob24gMy42IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxMzMzODcxNDYxIiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19jcHl0aG9uXzM2X2JvdCJ9LCB7InRva2VuIjogIjY5NTEwNDA4ODpBQUhmenlsSU9qU0lJUy1lT25JMjB5MkUyMEhvZEhzZnotMCIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOk9HUTFNRGd3WmpJd1pqRmwiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIFRyYXZpcyB1c2luZyBDUHl0aG9uIDMuNyIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTQ3ODI5MzcxNCIsICJib3RfdXNlcm5hbWUiOiAiQHB0Yl90cmF2aXNfY3B5dGhvbl8zN19ib3QifSwgeyJ0b2tlbiI6ICI2OTE0MjM1NTQ6QUFGOFdrakNaYm5IcVBfaTZHaFRZaXJGRWxackdhWU9oWDAiLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpZamM1TlRoaU1tUXlNV1ZoIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBvbiBUcmF2aXMgdXNpbmcgUHlQeSAyLjciLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDEzNjM5MzI1NzMiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfdHJhdmlzX3B5cHlfMjdfYm90In0sIHsidG9rZW4iOiAiNjg0MzM5OTg0OkFBRk1nRUVqcDAxcjVyQjAwN3lDZFZOc2c4QWxOc2FVLWNjIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TVRBek1UWTNNR1V5TmpnMCIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIFB5UHkgMy41IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxNDA3ODM2NjA1IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19weXB5XzM1X2JvdCJ9LCB7InRva2VuIjogIjY5MDA5MTM0NzpBQUZMbVI1cEFCNVljcGVfbU9oN3pNNEpGQk9oMHozVDBUbyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpEaGxOekU1TURrd1lXSmkiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIEFwcFZleW9yIHVzaW5nIENQeXRob24gMy40IiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxMjc5NjAwMDI2IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX2FwcHZleW9yX2NweXRob25fMzRfYm90In0sIHsidG9rZW4iOiAiNjk0MzA4MDUyOkFBRUIyX3NvbkNrNTVMWTlCRzlBTy1IOGp4aVBTNTVvb0JBIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WW1aaVlXWm1NakpoWkdNeSIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gQXBwVmV5b3IgdXNpbmcgQ1B5dGhvbiAyLjciLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDEyOTMwNzkxNjUiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfYXBwdmV5b3JfY3B5dGhvbl8yN19ib3QifSwgeyJ0b2tlbiI6ICIxMDU1Mzk3NDcxOkFBRzE4bkJfUzJXQXd1SjNnN29oS0JWZ1hYY2VNbklPeVNjIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TmpBd056QXpZalZpTkdOayIsICJuYW1lIjogIlBUQiB0ZXN0cyBbMF0iLCAic3VwZXJfZ3JvdXBfaWQiOiAiLTEwMDExODU1MDk2MzYiLCAidXNlcm5hbWUiOiAicHRiXzBfYm90In0sIHsidG9rZW4iOiAiMTA0NzMyNjc3MTpBQUY4bk90ODFGcFg4bGJidno4VWV3UVF2UmZUYkZmQnZ1SSIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOllUVTFOVEk0WkdSallqbGkiLCAibmFtZSI6ICJQVEIgdGVzdHMgWzFdIiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxNDg0Nzk3NjEyIiwgInVzZXJuYW1lIjogInB0Yl8xX2JvdCJ9LCB7InRva2VuIjogIjk3MTk5Mjc0NTpBQUdPa09hVzBOSGpnSXY1LTlqUWJPajR2R3FkaFNGLVV1cyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOk5XWmtNV1ZoWWpsallqVTUiLCAibmFtZSI6ICJQVEIgdGVzdHMgWzJdIiwgInN1cGVyX2dyb3VwX2lkIjogIi0xMDAxNDAyMjU1MDcwIiwgInVzZXJuYW1lIjogInB0Yl8yX2JvdCJ9XQ==
|
||||
TEST_BUILD: ${{ matrix.test-build }}
|
||||
TEST_PRE_COMMIT: ${{ matrix.test-pre-commit }}
|
||||
TEST_NO_PYTZ : "true"
|
||||
TEST_NO_PASSPORT: "true"
|
||||
TEST_BUILD: "true"
|
||||
shell: bash --noprofile --norc {0}
|
||||
|
||||
- name: Submit coverage
|
||||
|
||||
@@ -84,3 +84,6 @@ telegram.jpg
|
||||
|
||||
# Exclude .exrc file for Vim
|
||||
.exrc
|
||||
|
||||
# virtual env
|
||||
venv*
|
||||
|
||||
+34
-5
@@ -1,6 +1,6 @@
|
||||
# Make sure that
|
||||
# * the revs specified here match requirements-dev.txt
|
||||
# * the makefile checks the same files as pre-commit
|
||||
# * the additional_dependencies here match requirements.txt
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 20.8b1
|
||||
@@ -14,14 +14,43 @@ repos:
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/PyCQA/pylint
|
||||
rev: pylint-2.6.0
|
||||
rev: pylint-2.7.2
|
||||
hooks:
|
||||
- id: pylint
|
||||
files: ^(telegram|examples)/.*\.py$
|
||||
args:
|
||||
- --rcfile=setup.cfg
|
||||
- --rcfile=setup.cfg
|
||||
additional_dependencies:
|
||||
- certifi
|
||||
- tornado>=5.1
|
||||
- APScheduler==3.6.3
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v0.790
|
||||
rev: v0.812
|
||||
hooks:
|
||||
- id: mypy
|
||||
files: ^(telegram|examples)/.*\.py$
|
||||
name: mypy-ptb
|
||||
files: ^telegram/.*\.py$
|
||||
additional_dependencies:
|
||||
- certifi
|
||||
- tornado>=5.1
|
||||
- APScheduler==3.6.3
|
||||
- . # this basically does `pip install -e .`
|
||||
- id: mypy
|
||||
name: mypy-examples
|
||||
files: ^examples/.*\.py$
|
||||
args:
|
||||
- --no-strict-optional
|
||||
- --follow-imports=silent
|
||||
additional_dependencies:
|
||||
- certifi
|
||||
- tornado>=5.1
|
||||
- APScheduler==3.6.3
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.10.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
files: ^(telegram|examples|tests)/.*\.py$
|
||||
args:
|
||||
- --py36-plus
|
||||
|
||||
+17
-5
@@ -1,10 +1,22 @@
|
||||
# syntax: https://docs.readthedocs.io/en/latest/yaml-config.html
|
||||
# .readthedocs.yaml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/source/conf.py
|
||||
|
||||
# Optionally build your docs in additional formats such as PDF
|
||||
formats:
|
||||
- pdf
|
||||
- pdf
|
||||
|
||||
# Optionally set the version of Python and requirements required to build your docs
|
||||
python:
|
||||
setup_py_install: true
|
||||
version: 3
|
||||
|
||||
requirements_file: docs/requirements-docs.txt
|
||||
install:
|
||||
- method: pip
|
||||
path: .
|
||||
- requirements: docs/requirements-docs.txt
|
||||
|
||||
+10
-2
@@ -2,12 +2,20 @@ Credits
|
||||
=======
|
||||
|
||||
``python-telegram-bot`` was originally created by
|
||||
`Leandro Toledo <https://github.com/leandrotoledo>`_ and is now maintained by `Hinrich Mahler <https://github.com/Bibo-Joshi>`_.
|
||||
`Leandro Toledo <https://github.com/leandrotoledo>`_.
|
||||
The current development team includes
|
||||
|
||||
- `Hinrich Mahler <https://github.com/Bibo-Joshi>`_ (maintainer)
|
||||
- `Poolitzer <https://github.com/Poolitzer>`_ (community liaison)
|
||||
- `Shivam <https://github.com/Starry69>`_
|
||||
- `Harshil <https://github.com/harshil21>`_
|
||||
|
||||
Emeritus maintainers include
|
||||
`Jannes Höke <https://github.com/jh0ker>`_ (`@jh0ker <https://t.me/jh0ker>`_ on Telegram),
|
||||
`Noam Meltzer <https://github.com/tsnoam>`_, `Pieter Schutz <https://github.com/eldinnie>`_ and `Jasmin Bom <https://github.com/jsmnbom>`_.
|
||||
|
||||
The maintainers are actively supported by `Poolitzer <https://github.com/Poolitzer>`_ in terms of development and community liaison.
|
||||
Vendored packages
|
||||
-----------------
|
||||
|
||||
We're vendoring urllib3 as part of ``python-telegram-bot`` which is distributed under the MIT
|
||||
license. For more info, full credits & license terms, the sources can be found here:
|
||||
|
||||
+117
@@ -2,6 +2,123 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
Version 13.4
|
||||
============
|
||||
*Released 2021-03-14*
|
||||
|
||||
**Major Changes:**
|
||||
|
||||
- Full support of Bot API 5.1 (`#2424`_)
|
||||
|
||||
**Minor changes, CI improvements, doc fixes and type hinting:**
|
||||
|
||||
- Improve ``Updater.set_webhook`` (`#2419`_)
|
||||
- Doc Fixes (`#2404`_)
|
||||
- Type Hinting Fixes (`#2425`_)
|
||||
- Update ``pre-commit`` Settings (`#2415`_)
|
||||
- Fix Logging for Vendored ``urllib3`` (`#2427`_)
|
||||
- Stabilize Tests (`#2409`_)
|
||||
|
||||
.. _`#2424`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2424
|
||||
.. _`#2419`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2419
|
||||
.. _`#2404`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2404
|
||||
.. _`#2425`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2425
|
||||
.. _`#2415`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2415
|
||||
.. _`#2427`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2427
|
||||
.. _`#2409`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2409
|
||||
|
||||
Version 13.3
|
||||
============
|
||||
*Released 2021-02-19*
|
||||
|
||||
**Major Changes:**
|
||||
|
||||
- Make ``cryptography`` Dependency Optional & Refactor Some Tests (`#2386`_, `#2370`_)
|
||||
- Deprecate ``MessageQueue`` (`#2393`_)
|
||||
|
||||
**Bug Fixes:**
|
||||
|
||||
- Refactor ``Defaults`` Integration (`#2363`_)
|
||||
- Add Missing ``telegram.SecureValue`` to init and Docs (`#2398`_)
|
||||
|
||||
**Minor changes:**
|
||||
|
||||
- Doc Fixes (`#2359`_)
|
||||
|
||||
.. _`#2386`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2386
|
||||
.. _`#2370`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2370
|
||||
.. _`#2393`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2393
|
||||
.. _`#2363`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2363
|
||||
.. _`#2398`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2398
|
||||
.. _`#2359`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2359
|
||||
|
||||
Version 13.2
|
||||
============
|
||||
*Released 2021-02-02*
|
||||
|
||||
**Major Changes:**
|
||||
|
||||
- Introduce ``python-telegram-bot-raw`` (`#2324`_)
|
||||
- Explicit Signatures for Shortcuts (`#2240`_)
|
||||
|
||||
**New Features:**
|
||||
|
||||
- Add Missing Shortcuts to ``Message`` (`#2330`_)
|
||||
- Rich Comparison for ``Bot`` (`#2320`_)
|
||||
- Add ``run_async`` Parameter to ``ConversationHandler`` (`#2292`_)
|
||||
- Add New Shortcuts to ``Chat`` (`#2291`_)
|
||||
- Add New Constant ``MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH`` (`#2282`_)
|
||||
- Allow Passing Custom Filename For All Media (`#2249`_)
|
||||
- Handle Bytes as File Input (`#2233`_)
|
||||
|
||||
**Bug Fixes:**
|
||||
|
||||
- Fix Escaping in Nested Entities in ``Message`` Properties (`#2312`_)
|
||||
- Adjust Calling of ``Dispatcher.update_persistence`` (`#2285`_)
|
||||
- Add ``quote`` kwarg to ``Message.reply_copy`` (`#2232`_)
|
||||
- ``ConversationHandler``: Docs & ``edited_channel_post`` behavior (`#2339`_)
|
||||
|
||||
**Minor changes, CI improvements, doc fixes and type hinting:**
|
||||
|
||||
- Doc Fixes (`#2253`_, `#2225`_)
|
||||
- Reduce Usage of ``typing.Any`` (`#2321`_)
|
||||
- Extend Deeplinking Example (`#2335`_)
|
||||
- Add pyupgrade to pre-commit Hooks (`#2301`_)
|
||||
- Add PR Template (`#2299`_)
|
||||
- Drop Nightly Tests & Update Badges (`#2323`_)
|
||||
- Update Copyright (`#2289`_, `#2287`_)
|
||||
- Change Order of Class DocStrings (`#2256`_)
|
||||
- Add macOS to Test Matrix (`#2266`_)
|
||||
- Start Using Versioning Directives in Docs (`#2252`_)
|
||||
- Improve Annotations & Docs of Handlers (`#2243`_)
|
||||
|
||||
.. _`#2324`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2324
|
||||
.. _`#2240`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2240
|
||||
.. _`#2330`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2330
|
||||
.. _`#2320`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2320
|
||||
.. _`#2292`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2292
|
||||
.. _`#2291`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2291
|
||||
.. _`#2282`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2282
|
||||
.. _`#2249`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2249
|
||||
.. _`#2233`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2233
|
||||
.. _`#2312`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2312
|
||||
.. _`#2285`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2285
|
||||
.. _`#2232`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2232
|
||||
.. _`#2339`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2339
|
||||
.. _`#2253`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2253
|
||||
.. _`#2225`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2225
|
||||
.. _`#2321`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2321
|
||||
.. _`#2335`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2335
|
||||
.. _`#2301`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2301
|
||||
.. _`#2299`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2299
|
||||
.. _`#2323`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2323
|
||||
.. _`#2289`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2289
|
||||
.. _`#2287`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2287
|
||||
.. _`#2256`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2256
|
||||
.. _`#2266`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2266
|
||||
.. _`#2252`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2252
|
||||
.. _`#2243`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2243
|
||||
|
||||
Version 13.1
|
||||
============
|
||||
*Released 2020-11-29*
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
include LICENSE LICENSE.lesser Makefile requirements.txt py.typed
|
||||
include LICENSE LICENSE.lesser Makefile requirements.txt README_RAW.rst telegram/py.typed
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
.DEFAULT_GOAL := help
|
||||
.PHONY: clean pep8 black lint test install
|
||||
|
||||
PYLINT := pylint
|
||||
PYTEST := pytest
|
||||
PEP8 := flake8
|
||||
BLACK := black
|
||||
MYPY := mypy
|
||||
PIP := pip
|
||||
|
||||
clean:
|
||||
rm -fr build
|
||||
rm -fr dist
|
||||
find . -name '*.pyc' -exec rm -f {} \;
|
||||
find . -name '*.pyo' -exec rm -f {} \;
|
||||
find . -name '*~' -exec rm -f {} \;
|
||||
find . -regex "./telegram[0-9]*.\(jpg\|mp3\|mp4\|ogg\|png\|webp\)" -exec rm {} \;
|
||||
|
||||
pep8:
|
||||
$(PEP8) telegram tests examples
|
||||
|
||||
black:
|
||||
$(BLACK) .
|
||||
|
||||
lint:
|
||||
$(PYLINT) --rcfile=setup.cfg telegram examples
|
||||
|
||||
mypy:
|
||||
$(MYPY) -p telegram
|
||||
$(MYPY) examples
|
||||
|
||||
test:
|
||||
$(PYTEST) -v
|
||||
|
||||
install:
|
||||
$(PIP) install -r requirements.txt -r requirements-dev.txt
|
||||
|
||||
help:
|
||||
@echo "Available targets:"
|
||||
@echo "- clean Clean up the source directory"
|
||||
@echo "- pep8 Check style with flake8"
|
||||
@echo "- lint Check style with pylint"
|
||||
@echo "- black Check style with black"
|
||||
@echo "- mypy Check type hinting with mypy"
|
||||
@echo "- test Run tests using pytest"
|
||||
@echo
|
||||
@echo "Available variables:"
|
||||
@echo "- PYLINT default: $(PYLINT)"
|
||||
@echo "- PYTEST default: $(PYTEST)"
|
||||
@echo "- PEP8 default: $(PEP8)"
|
||||
@echo "- BLACK default: $(BLACK)"
|
||||
@echo "- MYPY default: $(MYPY)"
|
||||
@echo "- PIP default: $(PIP)"
|
||||
+39
-10
@@ -1,3 +1,6 @@
|
||||
..
|
||||
Make user to apply any changes to this file to README_RAW.rst as well!
|
||||
|
||||
.. image:: https://github.com/python-telegram-bot/logos/blob/master/logo-text/png/ptb-logo-text_768.png?raw=true
|
||||
:align: center
|
||||
:target: https://python-telegram-bot.org
|
||||
@@ -17,26 +20,30 @@ We have a vibrant community of developers helping each other in our `Telegram gr
|
||||
:target: https://pypi.org/project/python-telegram-bot/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://cpu.re/static/python-telegram-bot/downloads.svg
|
||||
:target: https://www.cpu.re/static/python-telegram-bot/downloads-by-python-version.txt
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-5.1-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/python-telegram-bot
|
||||
:target: https://pypistats.org/packages/python-telegram-bot
|
||||
:alt: PyPi Package Monthly Download
|
||||
|
||||
.. image:: https://img.shields.io/badge/docs-latest-af1a97.svg
|
||||
:target: https://python-telegram-bot.readthedocs.io/
|
||||
.. image:: https://readthedocs.org/projects/python-telegram-bot/badge/?version=stable
|
||||
:target: https://python-telegram-bot.readthedocs.io/en/stable/?badge=stable
|
||||
:alt: Documentation Status
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/python-telegram-bot.svg
|
||||
:target: https://www.gnu.org/licenses/lgpl-3.0.html
|
||||
:alt: LGPLv3 License
|
||||
|
||||
.. image:: https://github.com/python-telegram-bot/python-telegram-bot/workflows/GitHub%20Actions/badge.svg?event=schedule
|
||||
.. image:: https://github.com/python-telegram-bot/python-telegram-bot/workflows/GitHub%20Actions/badge.svg
|
||||
:target: https://github.com/python-telegram-bot/python-telegram-bot/
|
||||
:alt: Github Actions workflow
|
||||
|
||||
.. image:: https://codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg
|
||||
:target: https://codecov.io/gh/python-telegram-bot/python-telegram-bot
|
||||
:alt: Code coverage
|
||||
|
||||
|
||||
.. image:: http://isitmaintained.com/badge/resolution/python-telegram-bot/python-telegram-bot.svg
|
||||
:target: http://isitmaintained.com/project/python-telegram-bot/python-telegram-bot
|
||||
:alt: Median time to resolve an issue
|
||||
@@ -48,7 +55,7 @@ We have a vibrant community of developers helping each other in our `Telegram gr
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/psf/black
|
||||
|
||||
.. image:: https://img.shields.io/badge/Telegram-Group-blue.svg
|
||||
.. image:: https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram
|
||||
:target: https://telegram.me/pythontelegrambotgroup
|
||||
:alt: Telegram Group
|
||||
|
||||
@@ -92,11 +99,19 @@ In addition to the pure API implementation, this library features a number of hi
|
||||
make the development of bots easy and straightforward. These classes are contained in the
|
||||
``telegram.ext`` submodule.
|
||||
|
||||
A pure API implementation *without* ``telegram.ext`` is available as the standalone package ``python-telegram-bot-raw``. `See here for details. <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/README_RAW.rst>`_
|
||||
|
||||
----
|
||||
Note
|
||||
----
|
||||
|
||||
Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conjunction will result in undesired side-effects, so only install *one* of both.
|
||||
|
||||
====================
|
||||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **4.8** are supported.
|
||||
All types and methods of the Telegram Bot API **5.1** are supported.
|
||||
|
||||
==========
|
||||
Installing
|
||||
@@ -122,6 +137,16 @@ In case you have a previously cloned local repository already, you should initia
|
||||
|
||||
$ git submodule update --init --recursive
|
||||
|
||||
---------------------
|
||||
Optional Dependencies
|
||||
---------------------
|
||||
|
||||
PTB can be installed with optional dependencies:
|
||||
|
||||
* ``pip install python-telegram-bot[passport]`` installs the `cryptography <https://cryptography.io>`_ library. Use this, if you want to use Telegram Passport related functionality.
|
||||
* ``pip install python-telegram-bot[ujson]`` installs the `ujson <https://pypi.org/project/ujson/>`_ library. It will then be used for JSON de- & encoding, which can bring speed up compared to the standard `json <https://docs.python.org/3/library/json.html>`_ library.
|
||||
* ``pip install python-telegram-bot[socks]`` installs the `PySocks <https://pypi.org/project/PySocks/>`_ library. Use this, if you want to work behind a Socks5 server.
|
||||
|
||||
===============
|
||||
Getting started
|
||||
===============
|
||||
@@ -192,20 +217,24 @@ You can get help in several ways:
|
||||
|
||||
2. In case you are unable to join our group due to Telegram restrictions, you can use our `IRC channel <https://webchat.freenode.net/?channels=##python-telegram-bot>`_.
|
||||
|
||||
3. Report bugs, request new features or ask questions by `creating an issue <https://github.com/python-telegram-bot/python-telegram-bot/issues/new/choose>`_.
|
||||
3. Report bugs, request new features or ask questions by `creating an issue <https://github.com/python-telegram-bot/python-telegram-bot/issues/new/choose>`_ or `a discussion <https://github.com/python-telegram-bot/python-telegram-bot/discussions/new>`_.
|
||||
|
||||
4. Our `Wiki pages <https://github.com/python-telegram-bot/python-telegram-bot/wiki/>`_ offer a growing amount of resources.
|
||||
|
||||
5. You can even ask for help on Stack Overflow using the `python-telegram-bot tag <https://stackoverflow.com/questions/tagged/python-telegram-bot>`_.
|
||||
|
||||
|
||||
|
||||
============
|
||||
Contributing
|
||||
============
|
||||
|
||||
Contributions of all sizes are welcome. Please review our `contribution guidelines <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.github/CONTRIBUTING.rst>`_ to get started. You can also help by `reporting bugs <https://github.com/python-telegram-bot/python-telegram-bot/issues/new>`_.
|
||||
|
||||
========
|
||||
Donating
|
||||
========
|
||||
Occasionally we are asked if we accept donations to support the development. While we appreciate the thought, maintaining PTB is our hobby and we have almost no running costs for it. We therefore have nothing set up to accept donations. If you still want to donate, we kindly ask you to donate to another open source project/initiative of your choice instead.
|
||||
|
||||
=======
|
||||
License
|
||||
=======
|
||||
|
||||
+224
@@ -0,0 +1,224 @@
|
||||
..
|
||||
Make user to apply any changes to this file to README.rst as well!
|
||||
|
||||
.. image:: https://github.com/python-telegram-bot/logos/blob/master/logo-text/png/ptb-raw-logo-text_768.png?raw=true
|
||||
:align: center
|
||||
:target: https://python-telegram-bot.org
|
||||
:alt: python-telegram-bot-raw Logo
|
||||
|
||||
We have made you a wrapper you can't refuse
|
||||
|
||||
We have a vibrant community of developers helping each other in our `Telegram group <https://telegram.me/pythontelegrambotgroup>`_. Join us!
|
||||
|
||||
*Stay tuned for library updates and new releases on our* `Telegram Channel <https://telegram.me/pythontelegrambotchannel>`_.
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/python-telegram-bot-raw.svg
|
||||
:target: https://pypi.org/project/python-telegram-bot-raw/
|
||||
:alt: PyPi Package Version
|
||||
|
||||
.. image:: https://img.shields.io/pypi/pyversions/python-telegram-bot-raw.svg
|
||||
:target: https://pypi.org/project/python-telegram-bot-raw/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-5.1-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/python-telegram-bot-raw
|
||||
:target: https://pypistats.org/packages/python-telegram-bot-raw
|
||||
:alt: PyPi Package Monthly Download
|
||||
|
||||
.. image:: https://readthedocs.org/projects/python-telegram-bot/badge/?version=stable
|
||||
:target: https://python-telegram-bot.readthedocs.io/
|
||||
:alt: Documentation Status
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/python-telegram-bot-raw.svg
|
||||
:target: https://www.gnu.org/licenses/lgpl-3.0.html
|
||||
:alt: LGPLv3 License
|
||||
|
||||
.. image:: https://github.com/python-telegram-bot/python-telegram-bot/workflows/GitHub%20Actions/badge.svg
|
||||
:target: https://github.com/python-telegram-bot/python-telegram-bot/
|
||||
:alt: Github Actions workflow
|
||||
|
||||
.. image:: https://codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg
|
||||
:target: https://codecov.io/gh/python-telegram-bot/python-telegram-bot
|
||||
:alt: Code coverage
|
||||
|
||||
.. image:: http://isitmaintained.com/badge/resolution/python-telegram-bot/python-telegram-bot.svg
|
||||
:target: http://isitmaintained.com/project/python-telegram-bot/python-telegram-bot
|
||||
:alt: Median time to resolve an issue
|
||||
|
||||
.. image:: https://api.codacy.com/project/badge/Grade/99d901eaa09b44b4819aec05c330c968
|
||||
:target: https://www.codacy.com/app/python-telegram-bot/python-telegram-bot?utm_source=github.com&utm_medium=referral&utm_content=python-telegram-bot/python-telegram-bot&utm_campaign=Badge_Grade
|
||||
:alt: Code quality
|
||||
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/psf/black
|
||||
|
||||
.. image:: https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram
|
||||
:target: https://telegram.me/pythontelegrambotgroup
|
||||
:alt: Telegram Group
|
||||
|
||||
.. image:: https://img.shields.io/badge/IRC-Channel-blue.svg
|
||||
:target: https://webchat.freenode.net/?channels=##python-telegram-bot
|
||||
:alt: IRC Bridge
|
||||
|
||||
=================
|
||||
Table of contents
|
||||
=================
|
||||
|
||||
- `Introduction`_
|
||||
|
||||
- `Telegram API support`_
|
||||
|
||||
- `Installing`_
|
||||
|
||||
- `Getting started`_
|
||||
|
||||
#. `Logging`_
|
||||
|
||||
#. `Documentation`_
|
||||
|
||||
- `Getting help`_
|
||||
|
||||
- `Contributing`_
|
||||
|
||||
- `License`_
|
||||
|
||||
============
|
||||
Introduction
|
||||
============
|
||||
|
||||
This library provides a pure Python, lightweight interface for the
|
||||
`Telegram Bot API <https://core.telegram.org/bots/api>`_.
|
||||
It's compatible with Python versions 3.6+. PTB-Raw might also work on `PyPy <http://pypy.org/>`_, though there have been a lot of issues before. Hence, PyPy is not officially supported.
|
||||
|
||||
``python-telegram-bot-raw`` is part of the `python-telegram-bot <https://python-telegram-bot.org>`_ ecosystem and provides the pure API functionality extracted from PTB. It therefore does *not* have independent release schedules, changelogs or documentation. Please consult the PTB resources.
|
||||
|
||||
----
|
||||
Note
|
||||
----
|
||||
|
||||
Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conjunction will result in undesired side-effects, so only install *one* of both.
|
||||
|
||||
====================
|
||||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **5.1** are supported.
|
||||
|
||||
==========
|
||||
Installing
|
||||
==========
|
||||
|
||||
You can install or upgrade python-telegram-bot-raw with:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
$ pip install python-telegram-bot-raw --upgrade
|
||||
|
||||
Or you can install from source with:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
$ git clone https://github.com/python-telegram-bot/python-telegram-bot --recursive
|
||||
$ cd python-telegram-bot
|
||||
$ python setup-raw.py install
|
||||
|
||||
In case you have a previously cloned local repository already, you should initialize the added urllib3 submodule before installing with:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
$ git submodule update --init --recursive
|
||||
|
||||
----
|
||||
Note
|
||||
----
|
||||
|
||||
Installing the `.tar.gz` archive available on PyPi directly via `pip` will *not* work as expected, as `pip` does not recognize that it should use `setup-raw.py` instead of `setup.py`.
|
||||
|
||||
---------------------
|
||||
Optional Dependencies
|
||||
---------------------
|
||||
|
||||
PTB can be installed with optional dependencies:
|
||||
|
||||
* ``pip install python-telegram-bot-raw[passport]`` installs the `cryptography <https://cryptography.io>`_ library. Use this, if you want to use Telegram Passport related functionality.
|
||||
* ``pip install python-telegram-bot-raw[ujson]`` installs the `ujson <https://pypi.org/project/ujson/>`_ library. It will then be used for JSON de- & encoding, which can bring speed up compared to the standard `json <https://docs.python.org/3/library/json.html>`_ library.
|
||||
|
||||
===============
|
||||
Getting started
|
||||
===============
|
||||
|
||||
Our Wiki contains an `Introduction to the API <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Introduction-to-the-API>`_. Other references are:
|
||||
|
||||
- the `Telegram API documentation <https://core.telegram.org/bots/api>`_
|
||||
- the `python-telegram-bot documentation <https://python-telegram-bot.readthedocs.io/>`_
|
||||
|
||||
-------
|
||||
Logging
|
||||
-------
|
||||
|
||||
This library uses the ``logging`` module. To set up logging to standard output, put:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import logging
|
||||
logging.basicConfig(level=logging.DEBUG,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
|
||||
at the beginning of your script.
|
||||
|
||||
You can also use logs in your application by calling ``logging.getLogger()`` and setting the log level you want:
|
||||
|
||||
.. code:: python
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
If you want DEBUG logs instead:
|
||||
|
||||
.. code:: python
|
||||
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
=============
|
||||
Documentation
|
||||
=============
|
||||
|
||||
``python-telegram-bot``'s documentation lives at `readthedocs.io <https://python-telegram-bot.readthedocs.io/>`_, which
|
||||
includes the relevant documentation for ``python-telegram-bot-raw``.
|
||||
|
||||
============
|
||||
Getting help
|
||||
============
|
||||
|
||||
You can get help in several ways:
|
||||
|
||||
1. We have a vibrant community of developers helping each other in our `Telegram group <https://telegram.me/pythontelegrambotgroup>`_. Join us!
|
||||
|
||||
2. In case you are unable to join our group due to Telegram restrictions, you can use our `IRC channel <https://webchat.freenode.net/?channels=##python-telegram-bot>`_.
|
||||
|
||||
3. Report bugs, request new features or ask questions by `creating an issue <https://github.com/python-telegram-bot/python-telegram-bot/issues/new/choose>`_ or `a discussion <https://github.com/python-telegram-bot/python-telegram-bot/discussions/new>`_.
|
||||
|
||||
4. Our `Wiki pages <https://github.com/python-telegram-bot/python-telegram-bot/wiki/>`_ offer a growing amount of resources.
|
||||
|
||||
5. You can even ask for help on Stack Overflow using the `python-telegram-bot tag <https://stackoverflow.com/questions/tagged/python-telegram-bot>`_.
|
||||
|
||||
============
|
||||
Contributing
|
||||
============
|
||||
|
||||
Contributions of all sizes are welcome. Please review our `contribution guidelines <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.github/CONTRIBUTING.rst>`_ to get started. You can also help by `reporting bugs <https://github.com/python-telegram-bot/python-telegram-bot/issues/new>`_.
|
||||
|
||||
========
|
||||
Donating
|
||||
========
|
||||
Occasionally we are asked if we accept donations to support the development. While we appreciate the thought, maintaining PTB is our hobby and we have almost no running costs for it. We therefore have nothing set up to accept donations. If you still want to donate, we kindly ask you to donate to another open source project/initiative of your choice instead.
|
||||
|
||||
=======
|
||||
License
|
||||
=======
|
||||
|
||||
You may copy, distribute and modify the software provided that modifications are described and licensed for free under `LGPL-3 <https://www.gnu.org/licenses/lgpl-3.0.html>`_. Derivatives works (including modifications or anything statically linked to the library) can only be redistributed under LGPL-3, but applications that use the library don't have to be.
|
||||
@@ -1,3 +1,3 @@
|
||||
sphinx>=1.7.9
|
||||
sphinx_rtd_theme
|
||||
sphinx==3.5.2
|
||||
sphinx_rtd_theme==0.5.1
|
||||
sphinx-pypi-upload
|
||||
|
||||
+7
-4
@@ -24,7 +24,7 @@ sys.path.insert(0, os.path.abspath('../..'))
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
needs_sphinx = '1.7.9'
|
||||
needs_sphinx = '3.5.2'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
@@ -33,6 +33,9 @@ extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.napoleon'
|
||||
]
|
||||
# Don't show type hints in the signature - that just makes it hardly readable
|
||||
# and we document the types anyway
|
||||
autodoc_typehints = 'none'
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
@@ -50,7 +53,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Python Telegram Bot'
|
||||
copyright = u'2015-2020, Leandro Toledo'
|
||||
copyright = u'2015-2021, Leandro Toledo'
|
||||
author = u'Leandro Toledo'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
@@ -58,9 +61,9 @@ author = u'Leandro Toledo'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '13.1' # telegram.__version__[:3]
|
||||
version = '13.4' # telegram.__version__[:3]
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '13.1' # telegram.__version__
|
||||
release = '13.4' # telegram.__version__
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
telegram.ChatInviteLink
|
||||
=======================
|
||||
|
||||
.. autoclass:: telegram.ChatInviteLink
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
telegram.ChatMemberUpdated
|
||||
==========================
|
||||
|
||||
.. autoclass:: telegram.ChatMemberUpdated
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
telegram.ext.ChatMemberHandler
|
||||
==============================
|
||||
|
||||
.. autoclass:: telegram.ext.ChatMemberHandler
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -6,13 +6,12 @@ telegram.ext package
|
||||
telegram.ext.updater
|
||||
telegram.ext.dispatcher
|
||||
telegram.ext.dispatcherhandlerstop
|
||||
telegram.ext.filters
|
||||
telegram.ext.callbackcontext
|
||||
telegram.ext.defaults
|
||||
telegram.ext.job
|
||||
telegram.ext.jobqueue
|
||||
telegram.ext.messagequeue
|
||||
telegram.ext.delayqueue
|
||||
telegram.ext.callbackcontext
|
||||
telegram.ext.defaults
|
||||
|
||||
Handlers
|
||||
--------
|
||||
@@ -22,10 +21,12 @@ Handlers
|
||||
telegram.ext.handler
|
||||
telegram.ext.callbackqueryhandler
|
||||
telegram.ext.choseninlineresulthandler
|
||||
telegram.ext.conversationhandler
|
||||
telegram.ext.chatmemberhandler
|
||||
telegram.ext.commandhandler
|
||||
telegram.ext.conversationhandler
|
||||
telegram.ext.inlinequeryhandler
|
||||
telegram.ext.messagehandler
|
||||
telegram.ext.filters
|
||||
telegram.ext.pollanswerhandler
|
||||
telegram.ext.pollhandler
|
||||
telegram.ext.precheckoutqueryhandler
|
||||
@@ -43,4 +44,11 @@ Persistence
|
||||
|
||||
telegram.ext.basepersistence
|
||||
telegram.ext.picklepersistence
|
||||
telegram.ext.dictpersistence
|
||||
telegram.ext.dictpersistence
|
||||
|
||||
utils
|
||||
-----
|
||||
|
||||
.. toctree::
|
||||
|
||||
telegram.ext.utils.promise
|
||||
@@ -0,0 +1,6 @@
|
||||
telegram.ext.utils.promise.Promise
|
||||
==================================
|
||||
|
||||
.. autoclass:: telegram.ext.utils.promise.Promise
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
telegram.MessageAutoDeleteTimerChanged
|
||||
======================================
|
||||
|
||||
.. autoclass:: telegram.MessageAutoDeleteTimerChanged
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -13,8 +13,10 @@ telegram package
|
||||
telegram.callbackquery
|
||||
telegram.chat
|
||||
telegram.chataction
|
||||
telegram.chatinvitelink
|
||||
telegram.chatlocation
|
||||
telegram.chatmember
|
||||
telegram.chatmemberupdated
|
||||
telegram.chatpermissions
|
||||
telegram.chatphoto
|
||||
telegram.constants
|
||||
@@ -38,6 +40,7 @@ telegram package
|
||||
telegram.location
|
||||
telegram.loginurl
|
||||
telegram.message
|
||||
telegram.messageautodeletetimerchanged
|
||||
telegram.messageid
|
||||
telegram.messageentity
|
||||
telegram.parsemode
|
||||
@@ -57,6 +60,9 @@ telegram package
|
||||
telegram.video
|
||||
telegram.videonote
|
||||
telegram.voice
|
||||
telegram.voicechatstarted
|
||||
telegram.voicechatended
|
||||
telegram.voicechatparticipantsinvited
|
||||
telegram.webhookinfo
|
||||
|
||||
Stickers
|
||||
@@ -140,6 +146,7 @@ Passport
|
||||
telegram.credentials
|
||||
telegram.datacredentials
|
||||
telegram.securedata
|
||||
telegram.securevalue
|
||||
telegram.filecredentials
|
||||
telegram.iddocumentdata
|
||||
telegram.personaldetails
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
telegram.SecureValue
|
||||
====================
|
||||
|
||||
.. autoclass:: telegram.SecureValue
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -1,6 +1,9 @@
|
||||
telegram.utils.promise.Promise
|
||||
==============================
|
||||
|
||||
.. autoclass:: telegram.utils.promise.Promise
|
||||
:members:
|
||||
:show-inheritance:
|
||||
.. py:class:: telegram.utils.promise.Promise
|
||||
|
||||
Shortcut for :class:`telegram.ext.utils.promise.Promise`.
|
||||
|
||||
.. deprecated:: 13.2
|
||||
Use :class:`telegram.ext.utils.promise.Promise` instead.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
telegram.VoiceChatEnded
|
||||
=======================
|
||||
|
||||
.. autoclass:: telegram.VoiceChatEnded
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
telegram.VoiceChatParticipantsInvited
|
||||
=====================================
|
||||
|
||||
.. autoclass:: telegram.VoiceChatParticipantsInvited
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
telegram.VoiceChatStarted
|
||||
=========================
|
||||
|
||||
.. autoclass:: telegram.VoiceChatStarted
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
+14
-18
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -38,7 +36,7 @@ logger = logging.getLogger(__name__)
|
||||
GENDER, PHOTO, LOCATION, BIO = range(4)
|
||||
|
||||
|
||||
def start(update: Update, context: CallbackContext) -> int:
|
||||
def start(update: Update, _: CallbackContext) -> int:
|
||||
reply_keyboard = [['Boy', 'Girl', 'Other']]
|
||||
|
||||
update.message.reply_text(
|
||||
@@ -51,7 +49,7 @@ def start(update: Update, context: CallbackContext) -> int:
|
||||
return GENDER
|
||||
|
||||
|
||||
def gender(update: Update, context: CallbackContext) -> int:
|
||||
def gender(update: Update, _: CallbackContext) -> int:
|
||||
user = update.message.from_user
|
||||
logger.info("Gender of %s: %s", user.first_name, update.message.text)
|
||||
update.message.reply_text(
|
||||
@@ -63,52 +61,52 @@ def gender(update: Update, context: CallbackContext) -> int:
|
||||
return PHOTO
|
||||
|
||||
|
||||
def photo(update: Update, context: CallbackContext) -> int:
|
||||
def photo(update: Update, _: CallbackContext) -> int:
|
||||
user = update.message.from_user
|
||||
photo_file = update.message.photo[-1].get_file()
|
||||
photo_file.download('user_photo.jpg')
|
||||
logger.info("Photo of %s: %s", user.first_name, 'user_photo.jpg')
|
||||
update.message.reply_text(
|
||||
'Gorgeous! Now, send me your location please, ' 'or send /skip if you don\'t want to.'
|
||||
'Gorgeous! Now, send me your location please, or send /skip if you don\'t want to.'
|
||||
)
|
||||
|
||||
return LOCATION
|
||||
|
||||
|
||||
def skip_photo(update: Update, context: CallbackContext) -> int:
|
||||
def skip_photo(update: Update, _: CallbackContext) -> int:
|
||||
user = update.message.from_user
|
||||
logger.info("User %s did not send a photo.", user.first_name)
|
||||
update.message.reply_text(
|
||||
'I bet you look great! Now, send me your location please, ' 'or send /skip.'
|
||||
'I bet you look great! Now, send me your location please, or send /skip.'
|
||||
)
|
||||
|
||||
return LOCATION
|
||||
|
||||
|
||||
def location(update: Update, context: CallbackContext) -> int:
|
||||
def location(update: Update, _: CallbackContext) -> int:
|
||||
user = update.message.from_user
|
||||
user_location = update.message.location
|
||||
logger.info(
|
||||
"Location of %s: %f / %f", user.first_name, user_location.latitude, user_location.longitude
|
||||
)
|
||||
update.message.reply_text(
|
||||
'Maybe I can visit you sometime! ' 'At last, tell me something about yourself.'
|
||||
'Maybe I can visit you sometime! At last, tell me something about yourself.'
|
||||
)
|
||||
|
||||
return BIO
|
||||
|
||||
|
||||
def skip_location(update: Update, context: CallbackContext) -> int:
|
||||
def skip_location(update: Update, _: CallbackContext) -> int:
|
||||
user = update.message.from_user
|
||||
logger.info("User %s did not send a location.", user.first_name)
|
||||
update.message.reply_text(
|
||||
'You seem a bit paranoid! ' 'At last, tell me something about yourself.'
|
||||
'You seem a bit paranoid! At last, tell me something about yourself.'
|
||||
)
|
||||
|
||||
return BIO
|
||||
|
||||
|
||||
def bio(update: Update, context: CallbackContext) -> int:
|
||||
def bio(update: Update, _: CallbackContext) -> int:
|
||||
user = update.message.from_user
|
||||
logger.info("Bio of %s: %s", user.first_name, update.message.text)
|
||||
update.message.reply_text('Thank you! I hope we can talk again some day.')
|
||||
@@ -116,7 +114,7 @@ def bio(update: Update, context: CallbackContext) -> int:
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def cancel(update: Update, context: CallbackContext) -> int:
|
||||
def cancel(update: Update, _: CallbackContext) -> int:
|
||||
user = update.message.from_user
|
||||
logger.info("User %s canceled the conversation.", user.first_name)
|
||||
update.message.reply_text(
|
||||
@@ -128,9 +126,7 @@ def cancel(update: Update, context: CallbackContext) -> int:
|
||||
|
||||
def main() -> None:
|
||||
# Create the Updater and pass it your bot's token.
|
||||
# Make sure to set use_context=True to use the new context based callbacks
|
||||
# Post version 12 this will no longer be necessary
|
||||
updater = Updater("TOKEN", use_context=True)
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dispatcher = updater.dispatcher
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -55,7 +53,7 @@ def facts_to_str(user_data: Dict[str, str]) -> str:
|
||||
return "\n".join(facts).join(['\n', '\n'])
|
||||
|
||||
|
||||
def start(update: Update, context: CallbackContext) -> int:
|
||||
def start(update: Update, _: CallbackContext) -> int:
|
||||
update.message.reply_text(
|
||||
"Hi! My name is Doctor Botter. I will hold a more complex conversation with you. "
|
||||
"Why don't you tell me something about yourself?",
|
||||
@@ -73,9 +71,9 @@ def regular_choice(update: Update, context: CallbackContext) -> int:
|
||||
return TYPING_REPLY
|
||||
|
||||
|
||||
def custom_choice(update: Update, context: CallbackContext) -> int:
|
||||
def custom_choice(update: Update, _: CallbackContext) -> int:
|
||||
update.message.reply_text(
|
||||
'Alright, please send me the category first, ' 'for example "Most impressive skill"'
|
||||
'Alright, please send me the category first, for example "Most impressive skill"'
|
||||
)
|
||||
|
||||
return TYPING_CHOICE
|
||||
@@ -113,9 +111,7 @@ def done(update: Update, context: CallbackContext) -> int:
|
||||
|
||||
def main() -> None:
|
||||
# Create the Updater and pass it your bot's token.
|
||||
# Make sure to set use_context=True to use the new context based callbacks
|
||||
# Post version 12 this will no longer be necessary
|
||||
updater = Updater("TOKEN", use_context=True)
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dispatcher = updater.dispatcher
|
||||
|
||||
+51
-16
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""Bot that explains Telegram's "Deep Linking Parameters" functionality.
|
||||
@@ -23,27 +21,37 @@ bot.
|
||||
import logging
|
||||
|
||||
from telegram import ParseMode, InlineKeyboardMarkup, InlineKeyboardButton, Update
|
||||
from telegram.ext import Updater, CommandHandler, Filters, CallbackContext
|
||||
from telegram.ext import (
|
||||
Updater,
|
||||
CommandHandler,
|
||||
CallbackQueryHandler,
|
||||
Filters,
|
||||
CallbackContext,
|
||||
)
|
||||
|
||||
# Enable logging
|
||||
from telegram.utils import helpers
|
||||
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Define constants that will allow us to reuse the deep-linking parameters.
|
||||
CHECK_THIS_OUT = 'check-this-out'
|
||||
USING_ENTITIES = 'using-entities-here'
|
||||
SO_COOL = 'so-cool'
|
||||
CHECK_THIS_OUT = "check-this-out"
|
||||
USING_ENTITIES = "using-entities-here"
|
||||
USING_KEYBOARD = "using-keyboard-here"
|
||||
SO_COOL = "so-cool"
|
||||
|
||||
# Callback data to pass in 3rd level deeplinking
|
||||
KEYBOARD_CALLBACKDATA = "keyboard-callback-data"
|
||||
|
||||
|
||||
def start(update: Update, context: CallbackContext) -> None:
|
||||
"""Send a deep-linked URL when the command /start is issued."""
|
||||
bot = context.bot
|
||||
url = helpers.create_deep_linked_url(bot.get_me().username, CHECK_THIS_OUT, group=True)
|
||||
url = helpers.create_deep_linked_url(bot.username, CHECK_THIS_OUT, group=True)
|
||||
text = "Feel free to tell your friends about it:\n\n" + url
|
||||
update.message.reply_text(text)
|
||||
|
||||
@@ -51,13 +59,13 @@ def start(update: Update, context: CallbackContext) -> None:
|
||||
def deep_linked_level_1(update: Update, context: CallbackContext) -> None:
|
||||
"""Reached through the CHECK_THIS_OUT payload"""
|
||||
bot = context.bot
|
||||
url = helpers.create_deep_linked_url(bot.get_me().username, SO_COOL)
|
||||
url = helpers.create_deep_linked_url(bot.username, SO_COOL)
|
||||
text = (
|
||||
"Awesome, you just accessed hidden functionality! "
|
||||
" Now let's get back to the private chat."
|
||||
)
|
||||
keyboard = InlineKeyboardMarkup.from_button(
|
||||
InlineKeyboardButton(text='Continue here!', url=url)
|
||||
InlineKeyboardButton(text="Continue here!", url=url)
|
||||
)
|
||||
update.message.reply_text(text, reply_markup=keyboard)
|
||||
|
||||
@@ -65,23 +73,40 @@ def deep_linked_level_1(update: Update, context: CallbackContext) -> None:
|
||||
def deep_linked_level_2(update: Update, context: CallbackContext) -> None:
|
||||
"""Reached through the SO_COOL payload"""
|
||||
bot = context.bot
|
||||
url = helpers.create_deep_linked_url(bot.get_me().username, USING_ENTITIES)
|
||||
url = helpers.create_deep_linked_url(bot.username, USING_ENTITIES)
|
||||
text = f"You can also mask the deep-linked URLs as links: [▶️ CLICK HERE]({url})."
|
||||
update.message.reply_text(text, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True)
|
||||
|
||||
|
||||
def deep_linked_level_3(update: Update, context: CallbackContext) -> None:
|
||||
def deep_linked_level_3(update: Update, _: CallbackContext) -> None:
|
||||
"""Reached through the USING_ENTITIES payload"""
|
||||
update.message.reply_text(
|
||||
"It is also possible to make deep-linking using InlineKeyboardButtons.",
|
||||
reply_markup=InlineKeyboardMarkup(
|
||||
[[InlineKeyboardButton(text="Like this!", callback_data=KEYBOARD_CALLBACKDATA)]]
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def deep_link_level_3_callback(update: Update, context: CallbackContext) -> None:
|
||||
"""Answers CallbackQuery with deeplinking url."""
|
||||
bot = context.bot
|
||||
url = helpers.create_deep_linked_url(bot.username, USING_KEYBOARD)
|
||||
update.callback_query.answer(url=url)
|
||||
|
||||
|
||||
def deep_linked_level_4(update: Update, context: CallbackContext) -> None:
|
||||
"""Reached through the USING_KEYBOARD payload"""
|
||||
payload = context.args
|
||||
update.message.reply_text(
|
||||
f"Congratulations! This is as deep as it gets 👏🏻\n\nThe payload was: {payload}"
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
"""Start the bot."""
|
||||
# Create the Updater and pass it your bot's token.
|
||||
updater = Updater("TOKEN", use_context=True)
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dispatcher = updater.dispatcher
|
||||
@@ -102,6 +127,16 @@ def main():
|
||||
CommandHandler("start", deep_linked_level_3, Filters.regex(USING_ENTITIES), pass_args=True)
|
||||
)
|
||||
|
||||
# Possible with inline keyboard buttons aswell
|
||||
dispatcher.add_handler(
|
||||
CommandHandler("start", deep_linked_level_4, Filters.regex(USING_KEYBOARD))
|
||||
)
|
||||
|
||||
# register callback handler for inline keyboard button
|
||||
dispatcher.add_handler(
|
||||
CallbackQueryHandler(deep_link_level_3_callback, pattern=KEYBOARD_CALLBACKDATA)
|
||||
)
|
||||
|
||||
# Make sure the deep-linking handlers occur *before* the normal /start handler.
|
||||
dispatcher.add_handler(CommandHandler("start", start))
|
||||
|
||||
@@ -114,5 +149,5 @@ def main():
|
||||
updater.idle()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
+6
-10
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -32,27 +30,25 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
# Define a few command handlers. These usually take the two arguments update and
|
||||
# context. Error handlers also receive the raised TelegramError object in error.
|
||||
def start(update: Update, context: CallbackContext) -> None:
|
||||
def start(update: Update, _: CallbackContext) -> None:
|
||||
"""Send a message when the command /start is issued."""
|
||||
update.message.reply_text('Hi!')
|
||||
|
||||
|
||||
def help_command(update: Update, context: CallbackContext) -> None:
|
||||
def help_command(update: Update, _: CallbackContext) -> None:
|
||||
"""Send a message when the command /help is issued."""
|
||||
update.message.reply_text('Help!')
|
||||
|
||||
|
||||
def echo(update: Update, context: CallbackContext) -> None:
|
||||
def echo(update: Update, _: CallbackContext) -> None:
|
||||
"""Echo the user message."""
|
||||
update.message.reply_text(update.message.text)
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
"""Start the bot."""
|
||||
# Create the Updater and pass it your bot's token.
|
||||
# Make sure to set use_context=True to use the new context based callbacks
|
||||
# Post version 12 this will no longer be necessary
|
||||
updater = Updater("TOKEN", use_context=True)
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dispatcher = updater.dispatcher
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -29,7 +27,7 @@ BOT_TOKEN = "TOKEN"
|
||||
DEVELOPER_CHAT_ID = 123456789
|
||||
|
||||
|
||||
def error_handler(update: Update, context: CallbackContext) -> None:
|
||||
def error_handler(update: object, context: CallbackContext) -> 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)
|
||||
@@ -41,9 +39,10 @@ def error_handler(update: Update, context: CallbackContext) -> None:
|
||||
|
||||
# Build the message with some markup and additional information about what happened.
|
||||
# You might need to add some logic to deal with messages longer than the 4096 character limit.
|
||||
update_str = update.to_dict() if isinstance(update, Update) else str(update)
|
||||
message = (
|
||||
f'An exception was raised while handling an update\n'
|
||||
f'<pre>update = {html.escape(json.dumps(update.to_dict(), indent=2, ensure_ascii=False))}'
|
||||
f'<pre>update = {html.escape(json.dumps(update_str, indent=2, ensure_ascii=False))}'
|
||||
'</pre>\n\n'
|
||||
f'<pre>context.chat_data = {html.escape(str(context.chat_data))}</pre>\n\n'
|
||||
f'<pre>context.user_data = {html.escape(str(context.user_data))}</pre>\n\n'
|
||||
@@ -54,23 +53,21 @@ def error_handler(update: Update, context: CallbackContext) -> None:
|
||||
context.bot.send_message(chat_id=DEVELOPER_CHAT_ID, text=message, parse_mode=ParseMode.HTML)
|
||||
|
||||
|
||||
def bad_command(update: Update, context: CallbackContext) -> None:
|
||||
def bad_command(_: Update, context: CallbackContext) -> None:
|
||||
"""Raise an error to trigger the error handler."""
|
||||
context.bot.wrong_method_name()
|
||||
context.bot.wrong_method_name() # type: ignore[attr-defined]
|
||||
|
||||
|
||||
def start(update: Update, context: CallbackContext) -> None:
|
||||
def start(update: Update, _: CallbackContext) -> None:
|
||||
update.effective_message.reply_html(
|
||||
'Use /bad_command to cause an error.\n'
|
||||
f'Your chat id is <code>{update.effective_chat.id}</code>.'
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
# Create the Updater and pass it your bot's token.
|
||||
# Make sure to set use_context=True to use the new context based callbacks
|
||||
# Post version 12 this will no longer be necessary
|
||||
updater = Updater(BOT_TOKEN, use_context=True)
|
||||
updater = Updater(BOT_TOKEN)
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dispatcher = updater.dispatcher
|
||||
|
||||
+10
-12
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -31,32 +29,34 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
# Define a few command handlers. These usually take the two arguments update and
|
||||
# context. Error handlers also receive the raised TelegramError object in error.
|
||||
def start(update: Update, context: CallbackContext) -> None:
|
||||
def start(update: Update, _: CallbackContext) -> None:
|
||||
"""Send a message when the command /start is issued."""
|
||||
update.message.reply_text('Hi!')
|
||||
|
||||
|
||||
def help_command(update: Update, context: CallbackContext) -> None:
|
||||
def help_command(update: Update, _: CallbackContext) -> None:
|
||||
"""Send a message when the command /help is issued."""
|
||||
update.message.reply_text('Help!')
|
||||
|
||||
|
||||
def inlinequery(update: Update, context: CallbackContext) -> None:
|
||||
def inlinequery(update: Update, _: CallbackContext) -> None:
|
||||
"""Handle the inline query."""
|
||||
query = update.inline_query.query
|
||||
results = [
|
||||
InlineQueryResultArticle(
|
||||
id=uuid4(), title="Caps", input_message_content=InputTextMessageContent(query.upper())
|
||||
id=str(uuid4()),
|
||||
title="Caps",
|
||||
input_message_content=InputTextMessageContent(query.upper()),
|
||||
),
|
||||
InlineQueryResultArticle(
|
||||
id=uuid4(),
|
||||
id=str(uuid4()),
|
||||
title="Bold",
|
||||
input_message_content=InputTextMessageContent(
|
||||
f"*{escape_markdown(query)}*", parse_mode=ParseMode.MARKDOWN
|
||||
),
|
||||
),
|
||||
InlineQueryResultArticle(
|
||||
id=uuid4(),
|
||||
id=str(uuid4()),
|
||||
title="Italic",
|
||||
input_message_content=InputTextMessageContent(
|
||||
f"_{escape_markdown(query)}_", parse_mode=ParseMode.MARKDOWN
|
||||
@@ -69,9 +69,7 @@ def inlinequery(update: Update, context: CallbackContext) -> None:
|
||||
|
||||
def main() -> None:
|
||||
# Create the Updater and pass it your bot's token.
|
||||
# Make sure to set use_context=True to use the new context based callbacks
|
||||
# Post version 12 this will no longer be necessary
|
||||
updater = Updater("TOKEN", use_context=True)
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dispatcher = updater.dispatcher
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -18,7 +16,7 @@ logging.basicConfig(
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def start(update: Update, context: CallbackContext) -> None:
|
||||
def start(update: Update, _: CallbackContext) -> None:
|
||||
keyboard = [
|
||||
[
|
||||
InlineKeyboardButton("Option 1", callback_data='1'),
|
||||
@@ -32,7 +30,7 @@ def start(update: Update, context: CallbackContext) -> None:
|
||||
update.message.reply_text('Please choose:', reply_markup=reply_markup)
|
||||
|
||||
|
||||
def button(update: Update, context: CallbackContext) -> None:
|
||||
def button(update: Update, _: CallbackContext) -> None:
|
||||
query = update.callback_query
|
||||
|
||||
# CallbackQueries need to be answered, even if no notification to the user is needed
|
||||
@@ -42,15 +40,13 @@ def button(update: Update, context: CallbackContext) -> None:
|
||||
query.edit_message_text(text=f"Selected option: {query.data}")
|
||||
|
||||
|
||||
def help_command(update: Update, context: CallbackContext) -> None:
|
||||
def help_command(update: Update, _: CallbackContext) -> None:
|
||||
update.message.reply_text("Use /start to test this bot.")
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
# Create the Updater and pass it your bot's token.
|
||||
# Make sure to set use_context=True to use the new context based callbacks
|
||||
# Post version 12 this will no longer be necessary
|
||||
updater = Updater("TOKEN", use_context=True)
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
updater.dispatcher.add_handler(CommandHandler('start', start))
|
||||
updater.dispatcher.add_handler(CallbackQueryHandler(button))
|
||||
|
||||
+10
-12
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""Simple inline keyboard bot with multiple CallbackQueryHandlers.
|
||||
@@ -39,7 +37,7 @@ FIRST, SECOND = range(2)
|
||||
ONE, TWO, THREE, FOUR = range(4)
|
||||
|
||||
|
||||
def start(update: Update, context: CallbackContext) -> None:
|
||||
def start(update: Update, _: CallbackContext) -> int:
|
||||
"""Send message on `/start`."""
|
||||
# Get user that sent /start and log his name
|
||||
user = update.message.from_user
|
||||
@@ -61,7 +59,7 @@ def start(update: Update, context: CallbackContext) -> None:
|
||||
return FIRST
|
||||
|
||||
|
||||
def start_over(update: Update, context: CallbackContext) -> None:
|
||||
def start_over(update: Update, _: CallbackContext) -> int:
|
||||
"""Prompt same text & keyboard as `start` does but not as new message"""
|
||||
# Get CallbackQuery from Update
|
||||
query = update.callback_query
|
||||
@@ -82,7 +80,7 @@ def start_over(update: Update, context: CallbackContext) -> None:
|
||||
return FIRST
|
||||
|
||||
|
||||
def one(update: Update, context: CallbackContext) -> None:
|
||||
def one(update: Update, _: CallbackContext) -> int:
|
||||
"""Show new choice of buttons"""
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
@@ -99,7 +97,7 @@ def one(update: Update, context: CallbackContext) -> None:
|
||||
return FIRST
|
||||
|
||||
|
||||
def two(update: Update, context: CallbackContext) -> None:
|
||||
def two(update: Update, _: CallbackContext) -> int:
|
||||
"""Show new choice of buttons"""
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
@@ -116,7 +114,7 @@ def two(update: Update, context: CallbackContext) -> None:
|
||||
return FIRST
|
||||
|
||||
|
||||
def three(update: Update, context: CallbackContext) -> None:
|
||||
def three(update: Update, _: CallbackContext) -> int:
|
||||
"""Show new choice of buttons"""
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
@@ -134,7 +132,7 @@ def three(update: Update, context: CallbackContext) -> None:
|
||||
return SECOND
|
||||
|
||||
|
||||
def four(update: Update, context: CallbackContext) -> None:
|
||||
def four(update: Update, _: CallbackContext) -> int:
|
||||
"""Show new choice of buttons"""
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
@@ -151,7 +149,7 @@ def four(update: Update, context: CallbackContext) -> None:
|
||||
return FIRST
|
||||
|
||||
|
||||
def end(update: Update, context: CallbackContext) -> None:
|
||||
def end(update: Update, _: CallbackContext) -> int:
|
||||
"""Returns `ConversationHandler.END`, which tells the
|
||||
ConversationHandler that the conversation is over"""
|
||||
query = update.callback_query
|
||||
@@ -160,9 +158,9 @@ def end(update: Update, context: CallbackContext) -> None:
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
# Create the Updater and pass it your bot's token.
|
||||
updater = Updater("TOKEN", use_context=True)
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dispatcher = updater.dispatcher
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -17,6 +15,7 @@ bot.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Tuple, Dict, Any
|
||||
|
||||
from telegram import InlineKeyboardMarkup, InlineKeyboardButton, Update
|
||||
from telegram.ext import (
|
||||
@@ -65,14 +64,14 @@ END = ConversationHandler.END
|
||||
|
||||
|
||||
# Helper
|
||||
def _name_switcher(level):
|
||||
def _name_switcher(level: str) -> Tuple[str, str]:
|
||||
if level == PARENTS:
|
||||
return 'Father', 'Mother'
|
||||
return 'Brother', 'Sister'
|
||||
|
||||
|
||||
# Top level conversation callbacks
|
||||
def start(update: Update, context: CallbackContext) -> None:
|
||||
def start(update: Update, context: CallbackContext) -> str:
|
||||
"""Select an action: Adding parent/child or show data."""
|
||||
text = (
|
||||
'You may add a familiy member, yourself show the gathered data or end the '
|
||||
@@ -104,7 +103,7 @@ def start(update: Update, context: CallbackContext) -> None:
|
||||
return SELECTING_ACTION
|
||||
|
||||
|
||||
def adding_self(update: Update, context: CallbackContext) -> None:
|
||||
def adding_self(update: Update, context: CallbackContext) -> str:
|
||||
"""Add information about youself."""
|
||||
context.user_data[CURRENT_LEVEL] = SELF
|
||||
text = 'Okay, please tell me about yourself.'
|
||||
@@ -117,10 +116,10 @@ def adding_self(update: Update, context: CallbackContext) -> None:
|
||||
return DESCRIBING_SELF
|
||||
|
||||
|
||||
def show_data(update: Update, context: CallbackContext) -> None:
|
||||
def show_data(update: Update, context: CallbackContext) -> str:
|
||||
"""Pretty print gathered data."""
|
||||
|
||||
def prettyprint(user_data, level):
|
||||
def prettyprint(user_data: Dict[str, Any], level: str) -> str:
|
||||
people = user_data.get(level)
|
||||
if not people:
|
||||
return '\nNo information yet.'
|
||||
@@ -152,14 +151,14 @@ def show_data(update: Update, context: CallbackContext) -> None:
|
||||
return SHOWING
|
||||
|
||||
|
||||
def stop(update: Update, context: CallbackContext) -> None:
|
||||
def stop(update: Update, _: CallbackContext) -> int:
|
||||
"""End Conversation by command."""
|
||||
update.message.reply_text('Okay, bye.')
|
||||
|
||||
return END
|
||||
|
||||
|
||||
def end(update: Update, context: CallbackContext) -> None:
|
||||
def end(update: Update, _: CallbackContext) -> int:
|
||||
"""End conversation from InlineKeyboardButton."""
|
||||
update.callback_query.answer()
|
||||
|
||||
@@ -170,7 +169,7 @@ def end(update: Update, context: CallbackContext) -> None:
|
||||
|
||||
|
||||
# Second level conversation callbacks
|
||||
def select_level(update: Update, context: CallbackContext) -> None:
|
||||
def select_level(update: Update, _: CallbackContext) -> str:
|
||||
"""Choose to add a parent or a child."""
|
||||
text = 'You may add a parent or a child. Also you can show the gathered data or go back.'
|
||||
buttons = [
|
||||
@@ -191,7 +190,7 @@ def select_level(update: Update, context: CallbackContext) -> None:
|
||||
return SELECTING_LEVEL
|
||||
|
||||
|
||||
def select_gender(update: Update, context: CallbackContext) -> None:
|
||||
def select_gender(update: Update, context: CallbackContext) -> str:
|
||||
"""Choose to add mother or father."""
|
||||
level = update.callback_query.data
|
||||
context.user_data[CURRENT_LEVEL] = level
|
||||
@@ -218,7 +217,7 @@ def select_gender(update: Update, context: CallbackContext) -> None:
|
||||
return SELECTING_GENDER
|
||||
|
||||
|
||||
def end_second_level(update: Update, context: CallbackContext) -> None:
|
||||
def end_second_level(update: Update, context: CallbackContext) -> int:
|
||||
"""Return to top level conversation."""
|
||||
context.user_data[START_OVER] = True
|
||||
start(update, context)
|
||||
@@ -227,7 +226,7 @@ def end_second_level(update: Update, context: CallbackContext) -> None:
|
||||
|
||||
|
||||
# Third level callbacks
|
||||
def select_feature(update: Update, context: CallbackContext) -> None:
|
||||
def select_feature(update: Update, context: CallbackContext) -> str:
|
||||
"""Select a feature to update for the person."""
|
||||
buttons = [
|
||||
[
|
||||
@@ -254,7 +253,7 @@ def select_feature(update: Update, context: CallbackContext) -> None:
|
||||
return SELECTING_FEATURE
|
||||
|
||||
|
||||
def ask_for_input(update: Update, context: CallbackContext) -> None:
|
||||
def ask_for_input(update: Update, context: CallbackContext) -> str:
|
||||
"""Prompt user to input data for selected feature."""
|
||||
context.user_data[CURRENT_FEATURE] = update.callback_query.data
|
||||
text = 'Okay, tell me.'
|
||||
@@ -265,7 +264,7 @@ def ask_for_input(update: Update, context: CallbackContext) -> None:
|
||||
return TYPING
|
||||
|
||||
|
||||
def save_input(update: Update, context: CallbackContext) -> None:
|
||||
def save_input(update: Update, context: CallbackContext) -> str:
|
||||
"""Save input for feature and return to feature selection."""
|
||||
user_data = context.user_data
|
||||
user_data[FEATURES][user_data[CURRENT_FEATURE]] = update.message.text
|
||||
@@ -275,7 +274,7 @@ def save_input(update: Update, context: CallbackContext) -> None:
|
||||
return select_feature(update, context)
|
||||
|
||||
|
||||
def end_describing(update: Update, context: CallbackContext) -> None:
|
||||
def end_describing(update: Update, context: CallbackContext) -> int:
|
||||
"""End gathering of features and return to parent conversation."""
|
||||
user_data = context.user_data
|
||||
level = user_data[CURRENT_LEVEL]
|
||||
@@ -293,18 +292,16 @@ def end_describing(update: Update, context: CallbackContext) -> None:
|
||||
return END
|
||||
|
||||
|
||||
def stop_nested(update: Update, context: CallbackContext) -> None:
|
||||
def stop_nested(update: Update, _: CallbackContext) -> str:
|
||||
"""Completely end conversation from within nested conversation."""
|
||||
update.message.reply_text('Okay, bye.')
|
||||
|
||||
return STOPPING
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
# Create the Updater and pass it your bot's token.
|
||||
# Make sure to set use_context=True to use the new context based callbacks
|
||||
# Post version 12 this will no longer be necessary
|
||||
updater = Updater("TOKEN", use_context=True)
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dispatcher = updater.dispatcher
|
||||
|
||||
+12
-14
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -25,7 +23,7 @@ logging.basicConfig(
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def msg(update: Update, context: CallbackContext) -> None:
|
||||
def msg(update: Update, _: CallbackContext) -> None:
|
||||
# If we received any passport data
|
||||
passport_data = update.message.passport_data
|
||||
if passport_data:
|
||||
@@ -66,19 +64,19 @@ def msg(update: Update, context: CallbackContext) -> None:
|
||||
actual_file.download()
|
||||
if data.type in ('passport', 'driver_license', 'identity_card', 'internal_passport'):
|
||||
if data.front_side:
|
||||
file = data.front_side.get_file()
|
||||
print(data.type, file)
|
||||
file.download()
|
||||
front_file = data.front_side.get_file()
|
||||
print(data.type, front_file)
|
||||
front_file.download()
|
||||
if data.type in ('driver_license' and 'identity_card'):
|
||||
if data.reverse_side:
|
||||
file = data.reverse_side.get_file()
|
||||
print(data.type, file)
|
||||
file.download()
|
||||
reverse_file = data.reverse_side.get_file()
|
||||
print(data.type, reverse_file)
|
||||
reverse_file.download()
|
||||
if data.type in ('passport', 'driver_license', 'identity_card', 'internal_passport'):
|
||||
if data.selfie:
|
||||
file = data.selfie.get_file()
|
||||
print(data.type, file)
|
||||
file.download()
|
||||
selfie_file = data.selfie.get_file()
|
||||
print(data.type, selfie_file)
|
||||
selfie_file.download()
|
||||
if data.type in (
|
||||
'passport',
|
||||
'driver_license',
|
||||
@@ -97,7 +95,7 @@ def msg(update: Update, context: CallbackContext) -> None:
|
||||
actual_file.download()
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
"""Start the bot."""
|
||||
# Create the Updater and pass it your token and private key
|
||||
updater = Updater("TOKEN", private_key=open('private.key', 'rb').read())
|
||||
|
||||
+7
-11
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -29,7 +27,7 @@ logging.basicConfig(
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def start_callback(update: Update, context: CallbackContext) -> None:
|
||||
def start_callback(update: Update, _: CallbackContext) -> None:
|
||||
msg = "Use /shipping to get an invoice for shipping-payment, "
|
||||
msg += "or /noshipping for an invoice without shipping."
|
||||
update.message.reply_text(msg)
|
||||
@@ -92,7 +90,7 @@ def start_without_shipping_callback(update: Update, context: CallbackContext) ->
|
||||
)
|
||||
|
||||
|
||||
def shipping_callback(update: Update, context: CallbackContext) -> None:
|
||||
def shipping_callback(update: Update, _: CallbackContext) -> None:
|
||||
query = update.shipping_query
|
||||
# check the payload, is this from your bot?
|
||||
if query.invoice_payload != 'Custom-Payload':
|
||||
@@ -110,7 +108,7 @@ def shipping_callback(update: Update, context: CallbackContext) -> None:
|
||||
|
||||
|
||||
# after (optional) shipping, it's the pre-checkout
|
||||
def precheckout_callback(update: Update, context: CallbackContext) -> None:
|
||||
def precheckout_callback(update: Update, _: CallbackContext) -> None:
|
||||
query = update.pre_checkout_query
|
||||
# check the payload, is this from your bot?
|
||||
if query.invoice_payload != 'Custom-Payload':
|
||||
@@ -121,16 +119,14 @@ def precheckout_callback(update: Update, context: CallbackContext) -> None:
|
||||
|
||||
|
||||
# finally, after contacting the payment provider...
|
||||
def successful_payment_callback(update: Update, context: CallbackContext) -> None:
|
||||
def successful_payment_callback(update: Update, _: CallbackContext) -> None:
|
||||
# do something after successfully receiving payment?
|
||||
update.message.reply_text("Thank you for your payment!")
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
# Create the Updater and pass it your bot's token.
|
||||
# Make sure to set use_context=True to use the new context based callbacks
|
||||
# Post version 12 this will no longer be necessary
|
||||
updater = Updater("TOKEN", use_context=True)
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dispatcher = updater.dispatcher
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116, C0103
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -17,6 +15,7 @@ bot.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Dict
|
||||
|
||||
from telegram import ReplyKeyboardMarkup, Update
|
||||
from telegram.ext import (
|
||||
@@ -47,7 +46,7 @@ reply_keyboard = [
|
||||
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
|
||||
|
||||
|
||||
def facts_to_str(user_data):
|
||||
def facts_to_str(user_data: Dict[str, str]) -> str:
|
||||
facts = list()
|
||||
|
||||
for key, value in user_data.items():
|
||||
@@ -56,7 +55,7 @@ def facts_to_str(user_data):
|
||||
return "\n".join(facts).join(['\n', '\n'])
|
||||
|
||||
|
||||
def start(update: Update, context: CallbackContext) -> None:
|
||||
def start(update: Update, context: CallbackContext) -> int:
|
||||
reply_text = "Hi! My name is Doctor Botter."
|
||||
if context.user_data:
|
||||
reply_text += (
|
||||
@@ -73,7 +72,7 @@ def start(update: Update, context: CallbackContext) -> None:
|
||||
return CHOOSING
|
||||
|
||||
|
||||
def regular_choice(update: Update, context: CallbackContext) -> None:
|
||||
def regular_choice(update: Update, context: CallbackContext) -> int:
|
||||
text = update.message.text.lower()
|
||||
context.user_data['choice'] = text
|
||||
if context.user_data.get(text):
|
||||
@@ -87,7 +86,7 @@ def regular_choice(update: Update, context: CallbackContext) -> None:
|
||||
return TYPING_REPLY
|
||||
|
||||
|
||||
def custom_choice(update: Update, context: CallbackContext) -> None:
|
||||
def custom_choice(update: Update, _: CallbackContext) -> int:
|
||||
update.message.reply_text(
|
||||
'Alright, please send me the category first, ' 'for example "Most impressive skill"'
|
||||
)
|
||||
@@ -95,7 +94,7 @@ def custom_choice(update: Update, context: CallbackContext) -> None:
|
||||
return TYPING_CHOICE
|
||||
|
||||
|
||||
def received_information(update: Update, context: CallbackContext) -> None:
|
||||
def received_information(update: Update, context: CallbackContext) -> int:
|
||||
text = update.message.text
|
||||
category = context.user_data['choice']
|
||||
context.user_data[category] = text.lower()
|
||||
@@ -118,23 +117,23 @@ def show_data(update: Update, context: CallbackContext) -> None:
|
||||
)
|
||||
|
||||
|
||||
def done(update: Update, context: CallbackContext) -> None:
|
||||
def done(update: Update, context: CallbackContext) -> int:
|
||||
if 'choice' in context.user_data:
|
||||
del context.user_data['choice']
|
||||
|
||||
update.message.reply_text(
|
||||
"I learned these facts about you:" f"{facts_to_str(context.user_data)}" "Until next time!"
|
||||
"I learned these facts about you:" f"{facts_to_str(context.user_data)} Until next time!"
|
||||
)
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
# Create the Updater and pass it your bot's token.
|
||||
pp = PicklePersistence(filename='conversationbot')
|
||||
updater = Updater("TOKEN", persistence=pp, use_context=True)
|
||||
persistence = PicklePersistence(filename='conversationbot')
|
||||
updater = Updater("TOKEN", persistence=persistence)
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dp = updater.dispatcher
|
||||
dispatcher = updater.dispatcher
|
||||
|
||||
# Add conversation handler with the states CHOOSING, TYPING_CHOICE and TYPING_REPLY
|
||||
conv_handler = ConversationHandler(
|
||||
@@ -163,10 +162,10 @@ def main():
|
||||
persistent=True,
|
||||
)
|
||||
|
||||
dp.add_handler(conv_handler)
|
||||
dispatcher.add_handler(conv_handler)
|
||||
|
||||
show_data_handler = CommandHandler('show_data', show_data)
|
||||
dp.add_handler(show_data_handler)
|
||||
dispatcher.add_handler(show_data_handler)
|
||||
|
||||
# Start the Bot
|
||||
updater.start_polling()
|
||||
|
||||
+7
-11
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -36,7 +34,7 @@ logging.basicConfig(
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def start(update: Update, context: CallbackContext) -> None:
|
||||
def start(update: Update, _: CallbackContext) -> None:
|
||||
"""Inform user about what this bot can do"""
|
||||
update.message.reply_text(
|
||||
'Please select /poll to get a Poll, /quiz to get a Quiz or /preview'
|
||||
@@ -122,7 +120,7 @@ def receive_quiz_answer(update: Update, context: CallbackContext) -> None:
|
||||
context.bot.stop_poll(quiz_data["chat_id"], quiz_data["message_id"])
|
||||
|
||||
|
||||
def preview(update: Update, context: CallbackContext) -> None:
|
||||
def preview(update: Update, _: CallbackContext) -> None:
|
||||
"""Ask user to create a poll and display a preview of it"""
|
||||
# using this without a type lets the user chooses what he wants (quiz or poll)
|
||||
button = [[KeyboardButton("Press me!", request_poll=KeyboardButtonPollType())]]
|
||||
@@ -133,7 +131,7 @@ def preview(update: Update, context: CallbackContext) -> None:
|
||||
)
|
||||
|
||||
|
||||
def receive_poll(update: Update, context: CallbackContext) -> None:
|
||||
def receive_poll(update: Update, _: CallbackContext) -> None:
|
||||
"""On receiving polls, reply to it by a closed poll copying the received poll"""
|
||||
actual_poll = update.effective_message.poll
|
||||
# Only need to set the question and options, since all other parameters don't matter for
|
||||
@@ -147,16 +145,14 @@ def receive_poll(update: Update, context: CallbackContext) -> None:
|
||||
)
|
||||
|
||||
|
||||
def help_handler(update: Update, context: CallbackContext) -> None:
|
||||
def help_handler(update: Update, _: CallbackContext) -> None:
|
||||
"""Display a help message"""
|
||||
update.message.reply_text("Use /quiz, /poll or /preview to test this " "bot.")
|
||||
update.message.reply_text("Use /quiz, /poll or /preview to test this bot.")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# Create the Updater and pass it your bot's token.
|
||||
# Make sure to set use_context=True to use the new context based callbacks
|
||||
# Post version 12 this will no longer be necessary
|
||||
updater = Updater("TOKEN", use_context=True)
|
||||
updater = Updater("TOKEN")
|
||||
dispatcher = updater.dispatcher
|
||||
dispatcher.add_handler(CommandHandler('start', start))
|
||||
dispatcher.add_handler(CommandHandler('poll', poll))
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0603
|
||||
"""Simple Bot to reply to Telegram messages.
|
||||
|
||||
This is built on the API wrapper, see rawapibot.py to see the same example built
|
||||
This is built on the API wrapper, see echobot.py to see the same example built
|
||||
on the telegram.ext bot framework.
|
||||
This program is dedicated to the public domain under the CC0 license.
|
||||
"""
|
||||
@@ -40,7 +39,7 @@ def main() -> NoReturn:
|
||||
sleep(1)
|
||||
except Unauthorized:
|
||||
# The user has removed or blocked the bot.
|
||||
UPDATE_ID += 1 # type: ignore[operator]
|
||||
UPDATE_ID += 1
|
||||
|
||||
|
||||
def echo(bot: telegram.Bot) -> None:
|
||||
@@ -51,8 +50,9 @@ def echo(bot: telegram.Bot) -> None:
|
||||
UPDATE_ID = update.update_id + 1
|
||||
|
||||
if update.message: # your bot can receive updates without messages
|
||||
# Reply to the message
|
||||
update.message.reply_text(update.message.text)
|
||||
if update.message.text: # not all messages contain text
|
||||
# Reply to the message
|
||||
update.message.reply_text(update.message.text)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
+6
-10
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=W0613, C0116
|
||||
# type: ignore[union-attr]
|
||||
# pylint: disable=C0116
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -35,17 +33,17 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
# Define a few command handlers. These usually take the two arguments update and
|
||||
# context. Error handlers also receive the raised TelegramError object in error.
|
||||
def start(update: Update, context: CallbackContext) -> None:
|
||||
def start(update: Update, _: CallbackContext) -> None:
|
||||
update.message.reply_text('Hi! Use /set <seconds> to set a timer')
|
||||
|
||||
|
||||
def alarm(context):
|
||||
def alarm(context: CallbackContext) -> None:
|
||||
"""Send the alarm message."""
|
||||
job = context.job
|
||||
context.bot.send_message(job.context, text='Beep!')
|
||||
|
||||
|
||||
def remove_job_if_exists(name, context):
|
||||
def remove_job_if_exists(name: str, context: CallbackContext) -> bool:
|
||||
"""Remove job with given name. Returns whether job was removed."""
|
||||
current_jobs = context.job_queue.get_jobs_by_name(name)
|
||||
if not current_jobs:
|
||||
@@ -85,12 +83,10 @@ def unset(update: Update, context: CallbackContext) -> None:
|
||||
update.message.reply_text(text)
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
"""Run bot."""
|
||||
# Create the Updater and pass it your bot's token.
|
||||
# Make sure to set use_context=True to use the new context based callbacks
|
||||
# Post version 12 this will no longer be necessary
|
||||
updater = Updater("TOKEN", use_context=True)
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dispatcher = updater.dispatcher
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
# cryptography is an optional dependency, but running the tests properly requires it
|
||||
cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3
|
||||
|
||||
pre-commit
|
||||
# Make sure that the versions specified here match the pre-commit settings
|
||||
# Make sure that the versions specified here match the pre-commit settings!
|
||||
black==20.8b1
|
||||
flake8==3.8.4
|
||||
pylint==2.6.0
|
||||
mypy==0.790
|
||||
pylint==2.7.2
|
||||
mypy==0.812
|
||||
pyupgrade==2.10.0
|
||||
|
||||
pytest==4.2.0
|
||||
# Need older attrs version for pytest 4.2.0
|
||||
attrs==19.1.0
|
||||
pytest==6.2.2
|
||||
|
||||
flaky
|
||||
beautifulsoup4
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
# Make sure to install those as additional_dependencies in the
|
||||
# pre-commit hooks for pylint & mypy
|
||||
certifi
|
||||
# only telegram.ext: # Keep this line here; used in setup(-raw).py
|
||||
tornado>=5.1
|
||||
cryptography
|
||||
decorator>=4.4.0
|
||||
APScheduler==3.6.3
|
||||
pytz>=2018.6
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""The setup and build script for the python-telegram-bot-raw library."""
|
||||
|
||||
from setuptools import setup
|
||||
from setup import get_setup_kwargs
|
||||
|
||||
setup(**get_setup_kwargs(raw=True))
|
||||
@@ -13,7 +13,7 @@ upload-dir = docs/build/html
|
||||
max-line-length = 99
|
||||
ignore = W503, W605
|
||||
extend-ignore = E203
|
||||
exclude = setup.py, docs/source/conf.py, telegram/vendor
|
||||
exclude = setup.py, setup-raw.py docs/source/conf.py, telegram/vendor
|
||||
|
||||
[pylint]
|
||||
ignore=vendor
|
||||
@@ -27,7 +27,9 @@ addopts = --no-success-flaky-report -rsxX
|
||||
filterwarnings =
|
||||
error
|
||||
ignore::DeprecationWarning
|
||||
ignore::telegram.utils.deprecate.TelegramDeprecationWarning
|
||||
; 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
|
||||
|
||||
[coverage:run]
|
||||
branch = True
|
||||
@@ -59,6 +61,10 @@ ignore_errors = True
|
||||
[mypy-telegram.callbackquery,telegram.chat,telegram.message,telegram.user,telegram.files.*,telegram.inline.inlinequery,telegram.payment.precheckoutquery,telegram.payment.shippingquery,telegram.passport.passportdata,telegram.passport.credentials,telegram.passport.passportfile,telegram.ext.filters]
|
||||
strict_optional = False
|
||||
|
||||
# type hinting for asyncio in webhookhandler is a bit tricky because it depends on the OS
|
||||
[mypy-telegram.ext.utils.webhookhandler]
|
||||
warn_unused_ignores = False
|
||||
|
||||
[mypy-urllib3.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
|
||||
@@ -3,67 +3,122 @@
|
||||
|
||||
import codecs
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
UPSTREAM_URLLIB3_FLAG = '--with-upstream-urllib3'
|
||||
|
||||
def requirements():
|
||||
|
||||
def get_requirements(raw=False):
|
||||
"""Build the requirements list for this project"""
|
||||
requirements_list = []
|
||||
|
||||
with open('requirements.txt') as requirements:
|
||||
for install in requirements:
|
||||
with open('requirements.txt') as reqs:
|
||||
for install in reqs:
|
||||
if install.startswith('# only telegram.ext:'):
|
||||
if raw:
|
||||
break
|
||||
continue
|
||||
requirements_list.append(install.strip())
|
||||
|
||||
return requirements_list
|
||||
|
||||
|
||||
packages = find_packages(exclude=['tests*'])
|
||||
requirements = requirements()
|
||||
def get_packages_requirements(raw=False):
|
||||
"""Build the package & requirements list for this project"""
|
||||
reqs = get_requirements(raw=raw)
|
||||
|
||||
# Allow for a package install to not use the vendored urllib3
|
||||
UPSTREAM_URLLIB3_FLAG = '--with-upstream-urllib3'
|
||||
if UPSTREAM_URLLIB3_FLAG in sys.argv:
|
||||
sys.argv.remove(UPSTREAM_URLLIB3_FLAG)
|
||||
requirements.append('urllib3 >= 1.19.1')
|
||||
packages = [x for x in packages if not x.startswith('telegram.vendor.ptb_urllib3')]
|
||||
exclude = ['tests*']
|
||||
if raw:
|
||||
exclude.append('telegram.ext*')
|
||||
|
||||
packs = find_packages(exclude=exclude)
|
||||
# Allow for a package install to not use the vendored urllib3
|
||||
if UPSTREAM_URLLIB3_FLAG in sys.argv:
|
||||
sys.argv.remove(UPSTREAM_URLLIB3_FLAG)
|
||||
reqs.append('urllib3 >= 1.19.1')
|
||||
packs = [x for x in packs if not x.startswith('telegram.vendor.ptb_urllib3')]
|
||||
|
||||
return packs, reqs
|
||||
|
||||
|
||||
def get_setup_kwargs(raw=False):
|
||||
"""Builds a dictionary of kwargs for the setup function"""
|
||||
packages, requirements = get_packages_requirements(raw=raw)
|
||||
|
||||
raw_ext = "-raw" if raw else ""
|
||||
readme = f'README{"_RAW" if raw else ""}.rst'
|
||||
|
||||
with codecs.open('README.rst', 'r', 'utf-8') as fd:
|
||||
fn = os.path.join('telegram', 'version.py')
|
||||
with open(fn) as fh:
|
||||
code = compile(fh.read(), fn, 'exec')
|
||||
exec(code)
|
||||
|
||||
setup(name='python-telegram-bot',
|
||||
version=__version__,
|
||||
author='Leandro Toledo',
|
||||
author_email='devs@python-telegram-bot.org',
|
||||
license='LGPLv3',
|
||||
url='https://python-telegram-bot.org/',
|
||||
keywords='python telegram bot api wrapper',
|
||||
description="We have made you a wrapper you can't refuse",
|
||||
long_description=fd.read(),
|
||||
packages=packages,
|
||||
package_data={'telegram': ['py.typed']},
|
||||
install_requires=requirements,
|
||||
extras_require={
|
||||
'json': 'ujson',
|
||||
'socks': 'PySocks'
|
||||
},
|
||||
include_package_data=True,
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)',
|
||||
'Operating System :: OS Independent',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
'Topic :: Communications :: Chat',
|
||||
'Topic :: Internet',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
],)
|
||||
with open(readme, 'r', encoding='utf-8') as fd:
|
||||
|
||||
kwargs = dict(
|
||||
script_name=f'setup{raw_ext}.py',
|
||||
name=f'python-telegram-bot{raw_ext}',
|
||||
version=locals()['__version__'],
|
||||
author='Leandro Toledo',
|
||||
author_email='devs@python-telegram-bot.org',
|
||||
license='LGPLv3',
|
||||
url='https://python-telegram-bot.org/',
|
||||
# Keywords supported by PyPI can be found at https://git.io/JtLIZ
|
||||
project_urls={
|
||||
"Documentation": "https://python-telegram-bot.readthedocs.io",
|
||||
"Bug Tracker": "https://github.com/python-telegram-bot/python-telegram-bot/issues",
|
||||
"Source Code": "https://github.com/python-telegram-bot/python-telegram-bot",
|
||||
"News": "https://t.me/pythontelegrambotchannel",
|
||||
"Changelog": "https://python-telegram-bot.readthedocs.io/en/stable/changelog.html",
|
||||
},
|
||||
download_url=f'https://pypi.org/project/python-telegram-bot{raw_ext}/',
|
||||
keywords='python telegram bot api wrapper',
|
||||
description="We have made you a wrapper you can't refuse",
|
||||
long_description=fd.read(),
|
||||
long_description_content_type='text/x-rst',
|
||||
packages=packages,
|
||||
|
||||
install_requires=requirements,
|
||||
extras_require={
|
||||
'json': 'ujson',
|
||||
'socks': 'PySocks',
|
||||
# 3.4-3.4.3 contained some cyclical import bugs
|
||||
'passport': 'cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3',
|
||||
},
|
||||
include_package_data=True,
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)',
|
||||
'Operating System :: OS Independent',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
'Topic :: Communications :: Chat',
|
||||
'Topic :: Internet',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
],
|
||||
python_requires='>=3.6'
|
||||
)
|
||||
|
||||
return kwargs
|
||||
|
||||
|
||||
def main():
|
||||
# If we're building, build ptb-raw as well
|
||||
if set(sys.argv[1:]) in [{'bdist_wheel'}, {'sdist'}, {'sdist', 'bdist_wheel'}]:
|
||||
args = ['python', 'setup-raw.py']
|
||||
args.extend(sys.argv[1:])
|
||||
subprocess.run(args, check=True, capture_output=True)
|
||||
|
||||
setup(**get_setup_kwargs(raw=False))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
+88
-79
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -24,7 +24,9 @@ from .user import User
|
||||
from .files.chatphoto import ChatPhoto
|
||||
from .chat import Chat
|
||||
from .chatlocation import ChatLocation
|
||||
from .chatinvitelink import ChatInviteLink
|
||||
from .chatmember import ChatMember
|
||||
from .chatmemberupdated import ChatMemberUpdated
|
||||
from .chatpermissions import ChatPermissions
|
||||
from .files.photosize import PhotoSize
|
||||
from .files.audio import Audio
|
||||
@@ -40,8 +42,8 @@ from .files.videonote import VideoNote
|
||||
from .chataction import ChatAction
|
||||
from .dice import Dice
|
||||
from .userprofilephotos import UserProfilePhotos
|
||||
from .keyboardbutton import KeyboardButton
|
||||
from .keyboardbuttonpolltype import KeyboardButtonPollType
|
||||
from .keyboardbutton import KeyboardButton
|
||||
from .replymarkup import ReplyMarkup
|
||||
from .replykeyboardmarkup import ReplyKeyboardMarkup
|
||||
from .replykeyboardremove import ReplyKeyboardRemove
|
||||
@@ -54,6 +56,7 @@ from .messageentity import MessageEntity
|
||||
from .messageid import MessageId
|
||||
from .games.game import Game
|
||||
from .poll import Poll, PollOption, PollAnswer
|
||||
from .voicechat import VoiceChatStarted, VoiceChatEnded, VoiceChatParticipantsInvited
|
||||
from .loginurl import LoginUrl
|
||||
from .proximityalerttriggered import ProximityAlertTriggered
|
||||
from .games.callbackgame import CallbackGame
|
||||
@@ -68,6 +71,7 @@ from .passport.encryptedpassportelement import EncryptedPassportElement
|
||||
from .passport.passportdata import PassportData
|
||||
from .inline.inlinekeyboardbutton import InlineKeyboardButton
|
||||
from .inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
from .messageautodeletetimerchanged import MessageAutoDeleteTimerChanged
|
||||
from .message import Message
|
||||
from .callbackquery import CallbackQuery
|
||||
from .choseninlineresult import ChosenInlineResult
|
||||
@@ -139,32 +143,48 @@ from .passport.credentials import (
|
||||
Credentials,
|
||||
DataCredentials,
|
||||
SecureData,
|
||||
SecureValue,
|
||||
FileCredentials,
|
||||
TelegramDecryptionError,
|
||||
)
|
||||
from .bot import Bot
|
||||
from .version import __version__ # noqa: F401
|
||||
from .version import __version__, bot_api_version # noqa: F401
|
||||
|
||||
__author__ = 'devs@python-telegram-bot.org'
|
||||
|
||||
__all__ = [
|
||||
__all__ = ( # Keep this alphabetically ordered
|
||||
'Animation',
|
||||
'Audio',
|
||||
'Bot',
|
||||
'Chat',
|
||||
'ChatMember',
|
||||
'ChatPermissions',
|
||||
'ChatAction',
|
||||
'ChosenInlineResult',
|
||||
'BotCommand',
|
||||
'CallbackGame',
|
||||
'CallbackQuery',
|
||||
'Chat',
|
||||
'ChatAction',
|
||||
'ChatInviteLink',
|
||||
'ChatLocation',
|
||||
'ChatMember',
|
||||
'ChatMemberUpdated',
|
||||
'ChatPermissions',
|
||||
'ChatPhoto',
|
||||
'ChosenInlineResult',
|
||||
'Contact',
|
||||
'Credentials',
|
||||
'DataCredentials',
|
||||
'Dice',
|
||||
'Document',
|
||||
'EncryptedCredentials',
|
||||
'EncryptedPassportElement',
|
||||
'File',
|
||||
'FileCredentials',
|
||||
'ForceReply',
|
||||
'Game',
|
||||
'GameHighScore',
|
||||
'IdDocumentData',
|
||||
'InlineKeyboardButton',
|
||||
'InlineKeyboardMarkup',
|
||||
'InlineQuery',
|
||||
'InlineQueryResult',
|
||||
'InlineQueryResult',
|
||||
'InlineQueryResultArticle',
|
||||
'InlineQueryResultAudio',
|
||||
'InlineQueryResultCachedAudio',
|
||||
@@ -177,6 +197,7 @@ __all__ = [
|
||||
'InlineQueryResultCachedVoice',
|
||||
'InlineQueryResultContact',
|
||||
'InlineQueryResultDocument',
|
||||
'InlineQueryResultGame',
|
||||
'InlineQueryResultGif',
|
||||
'InlineQueryResultLocation',
|
||||
'InlineQueryResultMpeg4Gif',
|
||||
@@ -184,28 +205,71 @@ __all__ = [
|
||||
'InlineQueryResultVenue',
|
||||
'InlineQueryResultVideo',
|
||||
'InlineQueryResultVoice',
|
||||
'InlineQueryResultGame',
|
||||
'InputContactMessageContent',
|
||||
'InputFile',
|
||||
'InputLocationMessageContent',
|
||||
'InputMedia',
|
||||
'InputMediaAnimation',
|
||||
'InputMediaAudio',
|
||||
'InputMediaDocument',
|
||||
'InputMediaPhoto',
|
||||
'InputMediaVideo',
|
||||
'InputMessageContent',
|
||||
'InputTextMessageContent',
|
||||
'InputVenueMessageContent',
|
||||
'Invoice',
|
||||
'KeyboardButton',
|
||||
'KeyboardButtonPollType',
|
||||
'LabeledPrice',
|
||||
'Location',
|
||||
'ChatLocation',
|
||||
'ProximityAlertTriggered',
|
||||
'EncryptedCredentials',
|
||||
'PassportFile',
|
||||
'EncryptedPassportElement',
|
||||
'PassportData',
|
||||
'LoginUrl',
|
||||
'MAX_CAPTION_LENGTH',
|
||||
'MAX_FILESIZE_DOWNLOAD',
|
||||
'MAX_FILESIZE_UPLOAD',
|
||||
'MAX_MESSAGES_PER_MINUTE_PER_GROUP',
|
||||
'MAX_MESSAGES_PER_SECOND',
|
||||
'MAX_MESSAGES_PER_SECOND_PER_CHAT',
|
||||
'MAX_MESSAGE_LENGTH',
|
||||
'MaskPosition',
|
||||
'Message',
|
||||
'MessageAutoDeleteTimerChanged',
|
||||
'MessageEntity',
|
||||
'MessageId',
|
||||
'OrderInfo',
|
||||
'ParseMode',
|
||||
'PassportData',
|
||||
'PassportElementError',
|
||||
'PassportElementErrorDataField',
|
||||
'PassportElementErrorFile',
|
||||
'PassportElementErrorFiles',
|
||||
'PassportElementErrorFrontSide',
|
||||
'PassportElementErrorReverseSide',
|
||||
'PassportElementErrorSelfie',
|
||||
'PassportElementErrorTranslationFile',
|
||||
'PassportElementErrorTranslationFiles',
|
||||
'PassportElementErrorUnspecified',
|
||||
'PassportFile',
|
||||
'PersonalDetails',
|
||||
'PhotoSize',
|
||||
'ReplyKeyboardRemove',
|
||||
'Poll',
|
||||
'PollAnswer',
|
||||
'PollOption',
|
||||
'PreCheckoutQuery',
|
||||
'ProximityAlertTriggered',
|
||||
'ReplyKeyboardMarkup',
|
||||
'ReplyKeyboardRemove',
|
||||
'ReplyMarkup',
|
||||
'ResidentialAddress',
|
||||
'SUPPORTED_WEBHOOK_PORTS',
|
||||
'SecureData',
|
||||
'SecureValue',
|
||||
'ShippingAddress',
|
||||
'ShippingOption',
|
||||
'ShippingQuery',
|
||||
'Sticker',
|
||||
'StickerSet',
|
||||
'SuccessfulPayment',
|
||||
'TelegramDecryptionError',
|
||||
'TelegramError',
|
||||
'TelegramObject',
|
||||
'Update',
|
||||
@@ -213,65 +277,10 @@ __all__ = [
|
||||
'UserProfilePhotos',
|
||||
'Venue',
|
||||
'Video',
|
||||
'Voice',
|
||||
'MAX_MESSAGE_LENGTH',
|
||||
'MAX_CAPTION_LENGTH',
|
||||
'SUPPORTED_WEBHOOK_PORTS',
|
||||
'MAX_FILESIZE_DOWNLOAD',
|
||||
'MAX_FILESIZE_UPLOAD',
|
||||
'MAX_MESSAGES_PER_SECOND_PER_CHAT',
|
||||
'MAX_MESSAGES_PER_SECOND',
|
||||
'MAX_MESSAGES_PER_MINUTE_PER_GROUP',
|
||||
'WebhookInfo',
|
||||
'Animation',
|
||||
'Game',
|
||||
'GameHighScore',
|
||||
'VideoNote',
|
||||
'LabeledPrice',
|
||||
'SuccessfulPayment',
|
||||
'ShippingOption',
|
||||
'ShippingAddress',
|
||||
'PreCheckoutQuery',
|
||||
'OrderInfo',
|
||||
'Invoice',
|
||||
'ShippingQuery',
|
||||
'ChatPhoto',
|
||||
'StickerSet',
|
||||
'MaskPosition',
|
||||
'CallbackGame',
|
||||
'InputMedia',
|
||||
'InputMediaPhoto',
|
||||
'InputMediaVideo',
|
||||
'PassportElementError',
|
||||
'PassportElementErrorFile',
|
||||
'PassportElementErrorReverseSide',
|
||||
'PassportElementErrorFrontSide',
|
||||
'PassportElementErrorFiles',
|
||||
'PassportElementErrorDataField',
|
||||
'PassportElementErrorFile',
|
||||
'Credentials',
|
||||
'DataCredentials',
|
||||
'SecureData',
|
||||
'FileCredentials',
|
||||
'IdDocumentData',
|
||||
'PersonalDetails',
|
||||
'ResidentialAddress',
|
||||
'InputMediaVideo',
|
||||
'InputMediaAnimation',
|
||||
'InputMediaAudio',
|
||||
'InputMediaDocument',
|
||||
'TelegramDecryptionError',
|
||||
'PassportElementErrorSelfie',
|
||||
'PassportElementErrorTranslationFile',
|
||||
'PassportElementErrorTranslationFiles',
|
||||
'PassportElementErrorUnspecified',
|
||||
'Poll',
|
||||
'PollOption',
|
||||
'PollAnswer',
|
||||
'LoginUrl',
|
||||
'KeyboardButton',
|
||||
'KeyboardButtonPollType',
|
||||
'Dice',
|
||||
'BotCommand',
|
||||
'MessageId',
|
||||
]
|
||||
'Voice',
|
||||
'VoiceChatStarted',
|
||||
'VoiceChatEnded',
|
||||
'VoiceChatParticipantsInvited',
|
||||
'WebhookInfo',
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# !/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -16,7 +16,7 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
# pylint: disable=E0401, C0114
|
||||
# pylint: disable=C0114
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import Optional
|
||||
@@ -24,6 +24,7 @@ from typing import Optional
|
||||
import certifi
|
||||
|
||||
from . import __version__ as telegram_ver
|
||||
from .constants import BOT_API_VERSION
|
||||
|
||||
|
||||
def _git_revision() -> Optional[str]:
|
||||
@@ -39,6 +40,7 @@ def _git_revision() -> Optional[str]:
|
||||
def print_ver_info() -> None:
|
||||
git_revision = _git_revision()
|
||||
print(f'python-telegram-bot {telegram_ver}' + (f' ({git_revision})' if git_revision else ''))
|
||||
print(f'Bot API {BOT_API_VERSION}')
|
||||
print(f'certifi {certifi.__version__}') # type: ignore[attr-defined]
|
||||
sys_version = sys.version.replace('\n', ' ')
|
||||
print(f'Python {sys_version}')
|
||||
|
||||
+6
-11
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -23,7 +23,7 @@ except ImportError:
|
||||
import json # type: ignore[no-redef]
|
||||
|
||||
import warnings
|
||||
from typing import TYPE_CHECKING, Any, List, Optional, Tuple, Type, TypeVar
|
||||
from typing import TYPE_CHECKING, List, Optional, Tuple, Type, TypeVar
|
||||
|
||||
from telegram.utils.types import JSONDict
|
||||
|
||||
@@ -36,28 +36,23 @@ TO = TypeVar('TO', bound='TelegramObject', covariant=True)
|
||||
class TelegramObject:
|
||||
"""Base class for most telegram objects."""
|
||||
|
||||
# def __init__(self, *args: Any, **_kwargs: Any):
|
||||
# pass
|
||||
|
||||
_id_attrs: Tuple[Any, ...] = ()
|
||||
_id_attrs: Tuple[object, ...] = ()
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(self.to_dict())
|
||||
|
||||
def __getitem__(self, item: str) -> Any:
|
||||
def __getitem__(self, item: str) -> object:
|
||||
return self.__dict__[item]
|
||||
|
||||
@staticmethod
|
||||
def parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]:
|
||||
if not data:
|
||||
return None
|
||||
return data.copy()
|
||||
return None if data is None else data.copy()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls: Type[TO], data: Optional[JSONDict], bot: 'Bot') -> Optional[TO]:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
if data is None:
|
||||
return None
|
||||
|
||||
if cls == TelegramObject:
|
||||
|
||||
+1007
-638
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
# pylint: disable=R0903
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -30,14 +30,15 @@ class BotCommand(TelegramObject):
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`command` and :attr:`description` are equal.
|
||||
|
||||
Attributes:
|
||||
command (:obj:`str`): Text of the command.
|
||||
description (:obj:`str`): Description of the command.
|
||||
|
||||
Args:
|
||||
command (:obj:`str`): Text of the command, 1-32 characters. Can contain only lowercase
|
||||
English letters, digits and underscores.
|
||||
description (:obj:`str`): Description of the command, 3-256 characters.
|
||||
|
||||
Attributes:
|
||||
command (:obj:`str`): Text of the command.
|
||||
description (:obj:`str`): Description of the command.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, command: str, description: str, **_kwargs: Any):
|
||||
|
||||
+329
-59
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -18,13 +18,21 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
# pylint: disable=W0622
|
||||
"""This module contains an object that represents a Telegram CallbackQuery"""
|
||||
from typing import TYPE_CHECKING, Any, List, Optional, Union
|
||||
from typing import TYPE_CHECKING, Any, List, Optional, Union, Tuple, ClassVar
|
||||
|
||||
from telegram import Message, TelegramObject, User
|
||||
from telegram.utils.types import JSONDict
|
||||
from telegram import Message, TelegramObject, User, Location, ReplyMarkup, constants
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.types import JSONDict, ODVInput, DVInput
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, GameHighScore, InlineKeyboardMarkup, MessageId
|
||||
from telegram import (
|
||||
Bot,
|
||||
GameHighScore,
|
||||
InlineKeyboardMarkup,
|
||||
MessageId,
|
||||
InputMedia,
|
||||
MessageEntity,
|
||||
)
|
||||
|
||||
|
||||
class CallbackQuery(TelegramObject):
|
||||
@@ -39,21 +47,12 @@ class CallbackQuery(TelegramObject):
|
||||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Note:
|
||||
* In Python `from` is a reserved word, use `from_user` instead.
|
||||
* In Python ``from`` is a reserved word, use ``from_user`` instead.
|
||||
* Exactly one of the fields :attr:`data` or :attr:`game_short_name` will be present.
|
||||
|
||||
Attributes:
|
||||
id (:obj:`str`): Unique identifier for this query.
|
||||
from_user (:class:`telegram.User`): Sender.
|
||||
chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which
|
||||
the message with the callback button was sent.
|
||||
message (:class:`telegram.Message`): Optional. Message with the callback button that
|
||||
originated the query.
|
||||
data (:obj:`str`): Optional. Data associated with the callback button.
|
||||
inline_message_id (:obj:`str`): Optional. Identifier of the message sent via the bot in
|
||||
inline mode, that originated the query.
|
||||
game_short_name (:obj:`str`): Optional. Short name of a Game to be returned.
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
* After the user presses an inline button, Telegram clients will display a progress bar
|
||||
until you call :attr:`answer`. It is, therefore, necessary to react
|
||||
by calling :attr:`telegram.Bot.answer_callback_query` even if no notification to the user
|
||||
is needed (e.g., without specifying any of the optional parameters).
|
||||
|
||||
Args:
|
||||
id (:obj:`str`): Unique identifier for this query.
|
||||
@@ -71,11 +70,18 @@ class CallbackQuery(TelegramObject):
|
||||
the unique identifier for the game
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
|
||||
Note:
|
||||
After the user presses an inline button, Telegram clients will display a progress bar
|
||||
until you call :attr:`answer`. It is, therefore, necessary to react
|
||||
by calling :attr:`telegram.Bot.answer_callback_query` even if no notification to the user
|
||||
is needed (e.g., without specifying any of the optional parameters).
|
||||
Attributes:
|
||||
id (:obj:`str`): Unique identifier for this query.
|
||||
from_user (:class:`telegram.User`): Sender.
|
||||
chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which
|
||||
the message with the callback button was sent.
|
||||
message (:class:`telegram.Message`): Optional. Message with the callback button that
|
||||
originated the query.
|
||||
data (:obj:`str`): Optional. Data associated with the callback button.
|
||||
inline_message_id (:obj:`str`): Optional. Identifier of the message sent via the bot in
|
||||
inline mode, that originated the query.
|
||||
game_short_name (:obj:`str`): Optional. Short name of a Game to be returned.
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
|
||||
"""
|
||||
|
||||
@@ -117,18 +123,46 @@ class CallbackQuery(TelegramObject):
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def answer(self, *args: Any, **kwargs: Any) -> bool:
|
||||
def answer(
|
||||
self,
|
||||
text: str = None,
|
||||
show_alert: bool = False,
|
||||
url: str = None,
|
||||
cache_time: int = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.answer_callback_query(update.callback_query.id, *args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.answer_callback_query`.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
|
||||
"""
|
||||
return self.bot.answer_callback_query(self.id, *args, **kwargs)
|
||||
return self.bot.answer_callback_query(
|
||||
callback_query_id=self.id,
|
||||
text=text,
|
||||
show_alert=show_alert,
|
||||
url=url,
|
||||
cache_time=cache_time,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def edit_message_text(self, text: str, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
def edit_message_text(
|
||||
self,
|
||||
text: str,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: 'InlineKeyboardMarkup' = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
|
||||
) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
update.callback_query.message.edit_text(text, *args, **kwargs)
|
||||
@@ -138,6 +172,9 @@ class CallbackQuery(TelegramObject):
|
||||
bot.edit_message_text(text, inline_message_id=update.callback_query.inline_message_id,
|
||||
*args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.edit_message_text`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise :obj:`True` is returned.
|
||||
@@ -145,12 +182,35 @@ class CallbackQuery(TelegramObject):
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.edit_message_text(
|
||||
text, inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
inline_message_id=self.inline_message_id,
|
||||
text=text,
|
||||
parse_mode=parse_mode,
|
||||
disable_web_page_preview=disable_web_page_preview,
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
entities=entities,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
)
|
||||
return self.message.edit_text(text, *args, **kwargs)
|
||||
return self.message.edit_text(
|
||||
text=text,
|
||||
parse_mode=parse_mode,
|
||||
disable_web_page_preview=disable_web_page_preview,
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
entities=entities,
|
||||
)
|
||||
|
||||
def edit_message_caption(
|
||||
self, caption: str, *args: Any, **kwargs: Any
|
||||
self,
|
||||
caption: str = None,
|
||||
reply_markup: 'InlineKeyboardMarkup' = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
|
||||
) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
@@ -162,6 +222,9 @@ class CallbackQuery(TelegramObject):
|
||||
inline_message_id=update.callback_query.inline_message_id,
|
||||
*args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.edit_message_caption`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise :obj:`True` is returned.
|
||||
@@ -169,12 +232,30 @@ class CallbackQuery(TelegramObject):
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.edit_message_caption(
|
||||
caption=caption, inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
caption=caption,
|
||||
inline_message_id=self.inline_message_id,
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
parse_mode=parse_mode,
|
||||
api_kwargs=api_kwargs,
|
||||
caption_entities=caption_entities,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
)
|
||||
return self.message.edit_caption(caption=caption, *args, **kwargs)
|
||||
return self.message.edit_caption(
|
||||
caption=caption,
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
parse_mode=parse_mode,
|
||||
api_kwargs=api_kwargs,
|
||||
caption_entities=caption_entities,
|
||||
)
|
||||
|
||||
def edit_message_reply_markup(
|
||||
self, reply_markup: 'InlineKeyboardMarkup', *args: Any, **kwargs: Any
|
||||
self,
|
||||
reply_markup: Optional['InlineKeyboardMarkup'] = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
@@ -193,6 +274,9 @@ class CallbackQuery(TelegramObject):
|
||||
**kwargs
|
||||
)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.edit_message_reply_markup`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise :obj:`True` is returned.
|
||||
@@ -202,12 +286,24 @@ class CallbackQuery(TelegramObject):
|
||||
return self.bot.edit_message_reply_markup(
|
||||
reply_markup=reply_markup,
|
||||
inline_message_id=self.inline_message_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
)
|
||||
return self.message.edit_reply_markup(reply_markup=reply_markup, *args, **kwargs)
|
||||
return self.message.edit_reply_markup(
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def edit_message_media(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
def edit_message_media(
|
||||
self,
|
||||
media: 'InputMedia' = None,
|
||||
reply_markup: 'InlineKeyboardMarkup' = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
update.callback_query.message.edit_media(*args, **kwargs)
|
||||
@@ -217,6 +313,9 @@ class CallbackQuery(TelegramObject):
|
||||
bot.edit_message_media(inline_message_id=update.callback_query.inline_message_id,
|
||||
*args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.edit_message_media`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise :obj:`True` is returned.
|
||||
@@ -224,11 +323,33 @@ class CallbackQuery(TelegramObject):
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.edit_message_media(
|
||||
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
inline_message_id=self.inline_message_id,
|
||||
media=media,
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
)
|
||||
return self.message.edit_media(*args, **kwargs)
|
||||
return self.message.edit_media(
|
||||
media=media,
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def edit_message_live_location(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
def edit_message_live_location(
|
||||
self,
|
||||
latitude: float = None,
|
||||
longitude: float = None,
|
||||
location: Location = None,
|
||||
reply_markup: 'InlineKeyboardMarkup' = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
horizontal_accuracy: float = None,
|
||||
heading: int = None,
|
||||
proximity_alert_radius: int = None,
|
||||
) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
update.callback_query.message.edit_live_location(*args, **kwargs)
|
||||
@@ -240,6 +361,9 @@ class CallbackQuery(TelegramObject):
|
||||
*args, **kwargs
|
||||
)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.edit_message_live_location`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise :obj:`True` is returned.
|
||||
@@ -247,11 +371,37 @@ class CallbackQuery(TelegramObject):
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.edit_message_live_location(
|
||||
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
inline_message_id=self.inline_message_id,
|
||||
latitude=latitude,
|
||||
longitude=longitude,
|
||||
location=location,
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
horizontal_accuracy=horizontal_accuracy,
|
||||
heading=heading,
|
||||
proximity_alert_radius=proximity_alert_radius,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
)
|
||||
return self.message.edit_live_location(*args, **kwargs)
|
||||
return self.message.edit_live_location(
|
||||
latitude=latitude,
|
||||
longitude=longitude,
|
||||
location=location,
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
horizontal_accuracy=horizontal_accuracy,
|
||||
heading=heading,
|
||||
proximity_alert_radius=proximity_alert_radius,
|
||||
)
|
||||
|
||||
def stop_message_live_location(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
def stop_message_live_location(
|
||||
self,
|
||||
reply_markup: 'InlineKeyboardMarkup' = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
update.callback_query.message.stop_live_location(*args, **kwargs)
|
||||
@@ -263,6 +413,9 @@ class CallbackQuery(TelegramObject):
|
||||
*args, **kwargs
|
||||
)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.stop_message_live_location`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise :obj:`True` is returned.
|
||||
@@ -270,11 +423,28 @@ class CallbackQuery(TelegramObject):
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.stop_message_live_location(
|
||||
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
inline_message_id=self.inline_message_id,
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
)
|
||||
return self.message.stop_live_location(*args, **kwargs)
|
||||
return self.message.stop_live_location(
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def set_game_score(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
def set_game_score(
|
||||
self,
|
||||
user_id: Union[int, str],
|
||||
score: int,
|
||||
force: bool = None,
|
||||
disable_edit_message: bool = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
update.callback_query.message.set_game_score(*args, **kwargs)
|
||||
@@ -284,6 +454,9 @@ class CallbackQuery(TelegramObject):
|
||||
bot.set_game_score(inline_message_id=update.callback_query.inline_message_id,
|
||||
*args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.set_game_score`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise :obj:`True` is returned.
|
||||
@@ -291,11 +464,31 @@ class CallbackQuery(TelegramObject):
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.set_game_score(
|
||||
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
inline_message_id=self.inline_message_id,
|
||||
user_id=user_id,
|
||||
score=score,
|
||||
force=force,
|
||||
disable_edit_message=disable_edit_message,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
)
|
||||
return self.message.set_game_score(*args, **kwargs)
|
||||
return self.message.set_game_score(
|
||||
user_id=user_id,
|
||||
score=score,
|
||||
force=force,
|
||||
disable_edit_message=disable_edit_message,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def get_game_high_scores(self, *args: Any, **kwargs: Any) -> List['GameHighScore']:
|
||||
def get_game_high_scores(
|
||||
self,
|
||||
user_id: Union[int, str],
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> List['GameHighScore']:
|
||||
"""Shortcut for either::
|
||||
|
||||
update.callback_query.message.get_game_high_score(*args, **kwargs)
|
||||
@@ -305,28 +498,55 @@ class CallbackQuery(TelegramObject):
|
||||
bot.get_game_high_scores(inline_message_id=update.callback_query.inline_message_id,
|
||||
*args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.get_game_high_scores`.
|
||||
|
||||
Returns:
|
||||
List[:class:`telegram.GameHighScore`]
|
||||
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.get_game_high_scores(
|
||||
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
inline_message_id=self.inline_message_id,
|
||||
user_id=user_id,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
)
|
||||
return self.message.get_game_high_scores(*args, **kwargs)
|
||||
return self.message.get_game_high_scores(
|
||||
user_id=user_id,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def delete_message(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
def delete_message(
|
||||
self,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
update.callback_query.message.delete(*args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.delete_message`.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
|
||||
"""
|
||||
return self.message.delete(*args, **kwargs)
|
||||
return self.message.delete(
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def pin_message(self, *args: Any, **kwargs: Any) -> bool:
|
||||
def pin_message(
|
||||
self,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.pin_chat_message(chat_id=message.chat_id,
|
||||
@@ -334,13 +554,24 @@ class CallbackQuery(TelegramObject):
|
||||
*args,
|
||||
**kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.pin_chat_message`.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
|
||||
"""
|
||||
return self.message.pin(*args, **kwargs)
|
||||
return self.message.pin(
|
||||
disable_notification=disable_notification,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def unpin_message(self, *args: Any, **kwargs: Any) -> bool:
|
||||
def unpin_message(
|
||||
self,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.unpin_chat_message(chat_id=message.chat_id,
|
||||
@@ -348,13 +579,31 @@ class CallbackQuery(TelegramObject):
|
||||
*args,
|
||||
**kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.unpin_chat_message`.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
|
||||
"""
|
||||
return self.message.unpin(*args, **kwargs)
|
||||
return self.message.unpin(
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def copy_message(self, chat_id: int, *args: Any, **kwargs: Any) -> 'MessageId':
|
||||
def copy_message(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
caption: str = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: int = None,
|
||||
allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: ReplyMarkup = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> 'MessageId':
|
||||
"""Shortcut for::
|
||||
|
||||
update.callback_query.message.copy(
|
||||
@@ -364,8 +613,29 @@ class CallbackQuery(TelegramObject):
|
||||
*args,
|
||||
**kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.copy_message`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.MessageId`: On success, returns the MessageId of the sent message.
|
||||
|
||||
"""
|
||||
return self.message.copy(chat_id, *args, **kwargs)
|
||||
return self.message.copy(
|
||||
chat_id=chat_id,
|
||||
caption=caption,
|
||||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
disable_notification=disable_notification,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
MAX_ANSWER_TEXT_LENGTH: ClassVar[int] = constants.MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH
|
||||
"""
|
||||
:const:`telegram.constants.MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH`
|
||||
|
||||
.. versionadded:: 13.2
|
||||
"""
|
||||
|
||||
+1076
-107
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
# pylint: disable=R0903
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2021
|
||||
# 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 an invite link for a chat."""
|
||||
import datetime
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from telegram import TelegramObject, User
|
||||
from telegram.utils.helpers import from_timestamp, to_timestamp
|
||||
from telegram.utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class ChatInviteLink(TelegramObject):
|
||||
"""This object represents an invite link for a chat.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`invite_link`, :attr:`creator`, :attr:`is_primary` and
|
||||
:attr:`is_revoked` are equal.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Args:
|
||||
invite_link (:obj:`str`): The invite link.
|
||||
creator (:class:`telegram.User`): Creator of the link.
|
||||
is_primary (:obj:`bool`): :obj:`True`, if the link is primary.
|
||||
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.
|
||||
member_limit (:obj:`int`, optional): Maximum number of users that can be members of the
|
||||
chat simultaneously after joining the chat via this invite link; 1-99999.
|
||||
|
||||
Attributes:
|
||||
invite_link (:obj:`str`): The invite link. If the link was created by another chat
|
||||
administrator, then the second part of the link will be replaced with ``'…'``.
|
||||
creator (:class:`telegram.User`): Creator of the link.
|
||||
is_primary (:obj:`bool`): :obj:`True`, if the link is primary.
|
||||
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.
|
||||
member_limit (:obj:`int`): Optional. Maximum number of users that can be members
|
||||
of the chat simultaneously after joining the chat via this invite link; 1-99999.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
invite_link: str,
|
||||
creator: User,
|
||||
is_primary: bool,
|
||||
is_revoked: bool,
|
||||
expire_date: datetime.datetime = None,
|
||||
member_limit: int = None,
|
||||
**_kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.invite_link = invite_link
|
||||
self.creator = creator
|
||||
self.is_primary = is_primary
|
||||
self.is_revoked = is_revoked
|
||||
|
||||
# Optionals
|
||||
self.expire_date = expire_date
|
||||
self.member_limit = int(member_limit) if member_limit is not None else None
|
||||
|
||||
self._id_attrs = (self.invite_link, self.creator, self.is_primary, self.is_revoked)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatInviteLink']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data['creator'] = User.de_json(data.get('creator'), bot)
|
||||
data['expire_date'] = from_timestamp(data.get('expire_date', None))
|
||||
|
||||
return cls(**data)
|
||||
|
||||
def to_dict(self) -> JSONDict:
|
||||
data = super().to_dict()
|
||||
|
||||
data['expire_date'] = to_timestamp(self.expire_date)
|
||||
|
||||
return data
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -35,16 +35,16 @@ class ChatLocation(TelegramObject):
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`location` is equal.
|
||||
|
||||
Attributes:
|
||||
location (:class:`telegram.Location`): The location to which the supergroup is connected.
|
||||
address (:obj:`str`): Location address, as defined by the chat owner
|
||||
|
||||
Args:
|
||||
location (:class:`telegram.Location`): The location to which the supergroup is connected.
|
||||
Can't be a live location.
|
||||
address (:obj:`str`): Location address; 1-64 characters, as defined by the chat owner
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
Attributes:
|
||||
location (:class:`telegram.Location`): The location to which the supergroup is connected.
|
||||
address (:obj:`str`): Location address, as defined by the chat owner
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
+64
-37
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -34,42 +34,6 @@ class ChatMember(TelegramObject):
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`user` and :attr:`status` are equal.
|
||||
|
||||
Attributes:
|
||||
user (:class:`telegram.User`): Information about the user.
|
||||
status (:obj:`str`): The member's status in the chat.
|
||||
custom_title (:obj:`str`): Optional. Custom title for owner and administrators.
|
||||
is_anonymous (:obj:`bool`): Optional. :obj:`True`, if the user's presence in the chat is
|
||||
hidden.
|
||||
until_date (:class:`datetime.datetime`): Optional. Date when restrictions will be lifted
|
||||
for this user.
|
||||
can_be_edited (:obj:`bool`): Optional. If the bot is allowed to edit administrator
|
||||
privileges of that user.
|
||||
can_change_info (:obj:`bool`): Optional. If the user can change the chat title, photo and
|
||||
other settings.
|
||||
can_post_messages (:obj:`bool`): Optional. If the administrator can post in the channel.
|
||||
can_edit_messages (:obj:`bool`): Optional. If the administrator can edit messages of other
|
||||
users.
|
||||
can_delete_messages (:obj:`bool`): Optional. If the administrator can delete messages of
|
||||
other users.
|
||||
can_invite_users (:obj:`bool`): Optional. If the user can invite new users to the chat.
|
||||
can_restrict_members (:obj:`bool`): Optional. If the administrator can restrict, ban or
|
||||
unban chat members.
|
||||
can_pin_messages (:obj:`bool`): Optional. If the user can pin messages.
|
||||
can_promote_members (:obj:`bool`): Optional. If the administrator can add new
|
||||
administrators.
|
||||
is_member (:obj:`bool`): Optional. Restricted only. :obj:`True`, if the user is a member of
|
||||
the chat at the moment of the request.
|
||||
can_send_messages (:obj:`bool`): Optional. If the user can send text messages, contacts,
|
||||
locations and venues.
|
||||
can_send_media_messages (:obj:`bool`): Optional. If the user can send media messages,
|
||||
implies can_send_messages.
|
||||
can_send_polls (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to
|
||||
send polls.
|
||||
can_send_other_messages (:obj:`bool`): Optional. If the user can send animations, games,
|
||||
stickers and use inline bots, implies can_send_media_messages.
|
||||
can_add_web_page_previews (:obj:`bool`): Optional. If user may add web page previews to his
|
||||
messages, implies can_send_media_messages
|
||||
|
||||
Args:
|
||||
user (:class:`telegram.User`): Information about the user.
|
||||
status (:obj:`str`): The member's status in the chat. Can be 'creator', 'administrator',
|
||||
@@ -82,6 +46,18 @@ class ChatMember(TelegramObject):
|
||||
restrictions will be lifted for this user.
|
||||
can_be_edited (:obj:`bool`, optional): Administrators only. :obj:`True`, if the bot is
|
||||
allowed to edit administrator privileges of that user.
|
||||
can_manage_chat (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
|
||||
administrator can access the chat event log, chat statistics, message statistics in
|
||||
channels, see channel members, see anonymous administrators in supergroups and ignore
|
||||
slow mode. Implied by any other administrator privilege.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
can_manage_voice_chats (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
|
||||
administrator can manage voice chats.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
can_change_info (:obj:`bool`, optional): Administrators and restricted only. :obj:`True`,
|
||||
if the user can change the chat title, photo and other settings.
|
||||
can_post_messages (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
|
||||
@@ -113,6 +89,53 @@ class ChatMember(TelegramObject):
|
||||
can_add_web_page_previews (:obj:`bool`, optional): Restricted only. :obj:`True`, if user
|
||||
may add web page previews to his messages.
|
||||
|
||||
Attributes:
|
||||
user (:class:`telegram.User`): Information about the user.
|
||||
status (:obj:`str`): The member's status in the chat.
|
||||
custom_title (:obj:`str`): Optional. Custom title for owner and administrators.
|
||||
is_anonymous (:obj:`bool`): Optional. :obj:`True`, if the user's presence in the chat is
|
||||
hidden.
|
||||
until_date (:class:`datetime.datetime`): Optional. Date when restrictions will be lifted
|
||||
for this user.
|
||||
can_be_edited (:obj:`bool`): Optional. If the bot is allowed to edit administrator
|
||||
privileges of that user.
|
||||
can_manage_chat (:obj:`bool`): Optional. If the administrator can access the chat event
|
||||
log, chat statistics, message statistics in channels, see channel members, see
|
||||
anonymous administrators in supergroups and ignore slow mode.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
can_manage_voice_chats (:obj:`bool`): Optional. if the administrator can manage
|
||||
voice chats.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
can_change_info (:obj:`bool`): Optional. If the user can change the chat title, photo and
|
||||
other settings.
|
||||
can_post_messages (:obj:`bool`): Optional. If the administrator can post in the channel.
|
||||
can_edit_messages (:obj:`bool`): Optional. If the administrator can edit messages of other
|
||||
users.
|
||||
can_delete_messages (:obj:`bool`): Optional. If the administrator can delete messages of
|
||||
other users.
|
||||
can_invite_users (:obj:`bool`): Optional. If the user can invite new users to the chat.
|
||||
can_restrict_members (:obj:`bool`): Optional. If the administrator can restrict, ban or
|
||||
unban chat members.
|
||||
can_pin_messages (:obj:`bool`): Optional. If the user can pin messages.
|
||||
can_promote_members (:obj:`bool`): Optional. If the administrator can add new
|
||||
administrators.
|
||||
is_member (:obj:`bool`): Optional. Restricted only. :obj:`True`, if the user is a member of
|
||||
the chat at the moment of the request.
|
||||
can_send_messages (:obj:`bool`): Optional. If the user can send text messages, contacts,
|
||||
locations and venues.
|
||||
can_send_media_messages (:obj:`bool`): Optional. If the user can send media messages,
|
||||
implies can_send_messages.
|
||||
can_send_polls (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to
|
||||
send polls.
|
||||
can_send_other_messages (:obj:`bool`): Optional. If the user can send animations, games,
|
||||
stickers and use inline bots, implies can_send_media_messages.
|
||||
can_add_web_page_previews (:obj:`bool`): Optional. If user may add web page previews to his
|
||||
messages, implies can_send_media_messages
|
||||
|
||||
"""
|
||||
|
||||
ADMINISTRATOR: ClassVar[str] = constants.CHATMEMBER_ADMINISTRATOR
|
||||
@@ -150,6 +173,8 @@ class ChatMember(TelegramObject):
|
||||
is_member: bool = None,
|
||||
custom_title: str = None,
|
||||
is_anonymous: bool = None,
|
||||
can_manage_chat: bool = None,
|
||||
can_manage_voice_chats: bool = None,
|
||||
**_kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
@@ -175,6 +200,8 @@ class ChatMember(TelegramObject):
|
||||
self.can_send_other_messages = can_send_other_messages
|
||||
self.can_add_web_page_previews = can_add_web_page_previews
|
||||
self.is_member = is_member
|
||||
self.can_manage_chat = can_manage_chat
|
||||
self.can_manage_voice_chats = can_manage_voice_chats
|
||||
|
||||
self._id_attrs = (self.user, self.status)
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2021
|
||||
# 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 ChatMemberUpdated."""
|
||||
import datetime
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from telegram import TelegramObject, User, Chat, ChatMember, ChatInviteLink
|
||||
from telegram.utils.helpers import from_timestamp, to_timestamp
|
||||
from telegram.utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class ChatMemberUpdated(TelegramObject):
|
||||
"""This object represents changes in the status of a chat member.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`chat`, :attr:`from_user`, :attr:`date`,
|
||||
:attr:`old_chat_member` and :attr:`new_chat_member` are equal.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Note:
|
||||
In Python ``from`` is a reserved word, use ``from_user`` instead.
|
||||
|
||||
Args:
|
||||
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`.
|
||||
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.
|
||||
|
||||
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`.
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
chat: Chat,
|
||||
from_user: User,
|
||||
date: datetime.datetime,
|
||||
old_chat_member: ChatMember,
|
||||
new_chat_member: ChatMember,
|
||||
invite_link: ChatInviteLink = None,
|
||||
**_kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.chat = chat
|
||||
self.from_user = from_user
|
||||
self.date = date
|
||||
self.old_chat_member = old_chat_member
|
||||
self.new_chat_member = new_chat_member
|
||||
|
||||
# Optionals
|
||||
self.invite_link = invite_link
|
||||
|
||||
self._id_attrs = (
|
||||
self.chat,
|
||||
self.from_user,
|
||||
self.date,
|
||||
self.old_chat_member,
|
||||
self.new_chat_member,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatMemberUpdated']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data['chat'] = Chat.de_json(data.get('chat'), bot)
|
||||
data['from_user'] = User.de_json(data.get('from'), bot)
|
||||
data['date'] = from_timestamp(data.get('date'))
|
||||
data['old_chat_member'] = ChatMember.de_json(data.get('old_chat_member'), bot)
|
||||
data['new_chat_member'] = ChatMember.de_json(data.get('new_chat_member'), bot)
|
||||
data['invite_link'] = ChatInviteLink.de_json(data.get('invite_link'), bot)
|
||||
|
||||
return cls(**data)
|
||||
|
||||
def to_dict(self) -> JSONDict:
|
||||
data = super().to_dict()
|
||||
|
||||
# Required
|
||||
data['date'] = to_timestamp(self.date)
|
||||
|
||||
return data
|
||||
+21
-21
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -36,26 +36,6 @@ class ChatPermissions(TelegramObject):
|
||||
permissions that are set, but also sets all the others to :obj:`False`. However, since not
|
||||
documented, this behaviour may change unbeknown to PTB.
|
||||
|
||||
Attributes:
|
||||
can_send_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send text
|
||||
messages, contacts, locations and venues.
|
||||
can_send_media_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to
|
||||
send audios, documents, photos, videos, video notes and voice notes, implies
|
||||
:attr:`can_send_messages`.
|
||||
can_send_polls (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send polls,
|
||||
implies :attr:`can_send_messages`.
|
||||
can_send_other_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to
|
||||
send animations, games, stickers and use inline bots, implies
|
||||
:attr:`can_send_media_messages`.
|
||||
can_add_web_page_previews (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to
|
||||
add web page previews to their messages, implies :attr:`can_send_media_messages`.
|
||||
can_change_info (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to change the
|
||||
chat title, photo and other settings. Ignored in public supergroups.
|
||||
can_invite_users (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to invite
|
||||
new users to the chat.
|
||||
can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin
|
||||
messages. Ignored in public supergroups.
|
||||
|
||||
Args:
|
||||
can_send_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to send text
|
||||
messages, contacts, locations and venues.
|
||||
@@ -76,6 +56,26 @@ class ChatPermissions(TelegramObject):
|
||||
can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin
|
||||
messages. Ignored in public supergroups.
|
||||
|
||||
Attributes:
|
||||
can_send_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send text
|
||||
messages, contacts, locations and venues.
|
||||
can_send_media_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to
|
||||
send audios, documents, photos, videos, video notes and voice notes, implies
|
||||
:attr:`can_send_messages`.
|
||||
can_send_polls (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send polls,
|
||||
implies :attr:`can_send_messages`.
|
||||
can_send_other_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to
|
||||
send animations, games, stickers and use inline bots, implies
|
||||
:attr:`can_send_media_messages`.
|
||||
can_add_web_page_previews (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to
|
||||
add web page previews to their messages, implies :attr:`can_send_media_messages`.
|
||||
can_change_info (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to change the
|
||||
chat title, photo and other settings. Ignored in public supergroups.
|
||||
can_invite_users (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to invite
|
||||
new users to the chat.
|
||||
can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin
|
||||
messages. Ignored in public supergroups.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# pylint: disable=R0902,R0913
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -37,14 +37,9 @@ class ChosenInlineResult(TelegramObject):
|
||||
considered equal, if their :attr:`result_id` is equal.
|
||||
|
||||
Note:
|
||||
In Python `from` is a reserved word, use `from_user` instead.
|
||||
|
||||
Attributes:
|
||||
result_id (:obj:`str`): The unique identifier for the result that was chosen.
|
||||
from_user (:class:`telegram.User`): The user that chose the result.
|
||||
location (:class:`telegram.Location`): Optional. Sender location.
|
||||
inline_message_id (:obj:`str`): Optional. Identifier of the sent inline message.
|
||||
query (:obj:`str`): The query that was used to obtain the result.
|
||||
* In Python ``from`` is a reserved word, use ``from_user`` instead.
|
||||
* It is necessary to enable inline feedback via `@Botfather <https://t.me/BotFather>`_ in
|
||||
order to receive these objects in updates.
|
||||
|
||||
Args:
|
||||
result_id (:obj:`str`): The unique identifier for the result that was chosen.
|
||||
@@ -57,9 +52,12 @@ class ChosenInlineResult(TelegramObject):
|
||||
query (:obj:`str`): The query that was used to obtain the result.
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
Note:
|
||||
It is necessary to enable inline feedback via `@Botfather <https://t.me/BotFather>`_ in
|
||||
order to receive these objects in updates.
|
||||
Attributes:
|
||||
result_id (:obj:`str`): The unique identifier for the result that was chosen.
|
||||
from_user (:class:`telegram.User`): The user that chose the result.
|
||||
location (:class:`telegram.Location`): Optional. Sender location.
|
||||
inline_message_id (:obj:`str`): Optional. Identifier of the sent inline message.
|
||||
query (:obj:`str`): The query that was used to obtain the result.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
+18
-1
@@ -1,5 +1,5 @@
|
||||
# python-telegram-bot - a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# by the python-telegram-bot contributors <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -21,6 +21,10 @@ The following constants were extracted from the
|
||||
`Telegram Bots API <https://core.telegram.org/bots/api>`_.
|
||||
|
||||
Attributes:
|
||||
BOT_API_VERSION (:obj:`str`): `5.1`. Telegram Bot API version supported by this
|
||||
version of `python-telegram-bot`. Also available as ``telegram.bot_api_version``.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
MAX_MESSAGE_LENGTH (:obj:`int`): 4096
|
||||
MAX_CAPTION_LENGTH (:obj:`int`): 1024
|
||||
SUPPORTED_WEBHOOK_PORTS (List[:obj:`int`]): [443, 80, 88, 8443]
|
||||
@@ -32,6 +36,9 @@ Attributes:
|
||||
MAX_MESSAGES_PER_SECOND (:obj:`int`): 30
|
||||
MAX_MESSAGES_PER_MINUTE_PER_GROUP (:obj:`int`): 20
|
||||
MAX_INLINE_QUERY_RESULTS (:obj:`int`): 50
|
||||
MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH (:obj:`int`): 200
|
||||
|
||||
.. versionadded:: 13.2
|
||||
|
||||
The following constant have been found by experimentation:
|
||||
|
||||
@@ -85,8 +92,14 @@ Attributes:
|
||||
DICE_BASKETBALL (:obj:`str`): '🏀'
|
||||
DICE_FOOTBALL (:obj:`str`): '⚽'
|
||||
DICE_SLOT_MACHINE (:obj:`str`): '🎰'
|
||||
DICE_BOWLING (:obj:`str`): '🎳'
|
||||
|
||||
.. versionadded:: 13.4
|
||||
DICE_ALL_EMOJI (List[:obj:`str`]): List of all supported base emoji.
|
||||
|
||||
.. versionchanged:: 13.4
|
||||
Added :attr:`DICE_BOWLING`
|
||||
|
||||
:class:`telegram.MessageEntity`:
|
||||
|
||||
Attributes:
|
||||
@@ -133,6 +146,7 @@ Attributes:
|
||||
"""
|
||||
from typing import List
|
||||
|
||||
BOT_API_VERSION: str = '5.1'
|
||||
MAX_MESSAGE_LENGTH: int = 4096
|
||||
MAX_CAPTION_LENGTH: int = 1024
|
||||
ANONYMOUS_ADMIN_ID: int = 1087968824
|
||||
@@ -149,6 +163,7 @@ MAX_MESSAGES_PER_SECOND: int = 30
|
||||
MAX_MESSAGES_PER_MINUTE_PER_GROUP: int = 20
|
||||
MAX_MESSAGE_ENTITIES: int = 100
|
||||
MAX_INLINE_QUERY_RESULTS: int = 50
|
||||
MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH: int = 200
|
||||
|
||||
CHAT_PRIVATE: str = 'private'
|
||||
CHAT_GROUP: str = 'group'
|
||||
@@ -178,12 +193,14 @@ DICE_DARTS: str = '🎯'
|
||||
DICE_BASKETBALL: str = '🏀'
|
||||
DICE_FOOTBALL: str = '⚽'
|
||||
DICE_SLOT_MACHINE: str = '🎰'
|
||||
DICE_BOWLING: str = '🎳'
|
||||
DICE_ALL_EMOJI: List[str] = [
|
||||
DICE_DICE,
|
||||
DICE_DARTS,
|
||||
DICE_BASKETBALL,
|
||||
DICE_FOOTBALL,
|
||||
DICE_SLOT_MACHINE,
|
||||
DICE_BOWLING,
|
||||
]
|
||||
|
||||
MESSAGEENTITY_MENTION: str = 'mention'
|
||||
|
||||
+17
-6
@@ -2,7 +2,7 @@
|
||||
# pylint: disable=R0903
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -41,22 +41,27 @@ class Dice(TelegramObject):
|
||||
3 indicates that the basket was missed. However, this behaviour is undocumented and might
|
||||
be changed by Telegram.
|
||||
|
||||
If :attr:`emoji` is "⚽", a value of 3 to 5 currently scores a goal, while a value of 1 to
|
||||
If :attr:`emoji` is "⚽", a value of 4 to 5 currently scores a goal, while a value of 1 to
|
||||
3 indicates that the goal was missed. However, this behaviour is undocumented and might
|
||||
be changed by Telegram.
|
||||
|
||||
If :attr:`emoji` is "🎳", a value of 6 knocks all the pins, while a value of 1 means all
|
||||
the pins were missed. However, this behaviour is undocumented and might be changed by
|
||||
Telegram.
|
||||
|
||||
If :attr:`emoji` is "🎰", each value corresponds to a unique combination of symbols, which
|
||||
can be found at our `wiki <https://git.io/JkeC6>`_. However, this behaviour is undocumented
|
||||
and might be changed by Telegram.
|
||||
|
||||
Args:
|
||||
value (:obj:`int`): Value of the dice. 1-6 for dice, darts and bowling balls, 1-5 for
|
||||
basketball and football/soccer ball, 1-64 for slot machine.
|
||||
emoji (:obj:`str`): Emoji on which the dice throw animation is based.
|
||||
|
||||
Attributes:
|
||||
value (:obj:`int`): Value of the dice.
|
||||
emoji (:obj:`str`): Emoji on which the dice throw animation is based.
|
||||
|
||||
Args:
|
||||
value (:obj:`int`): Value of the dice. 1-6 for dice and darts, 1-5 for basketball and
|
||||
football/soccer ball, 1-64 for slot machine.
|
||||
emoji (:obj:`str`): Emoji on which the dice throw animation is based.
|
||||
"""
|
||||
|
||||
def __init__(self, value: int, emoji: str, **_kwargs: Any):
|
||||
@@ -75,5 +80,11 @@ class Dice(TelegramObject):
|
||||
""":const:`telegram.constants.DICE_FOOTBALL`"""
|
||||
SLOT_MACHINE: ClassVar[str] = constants.DICE_SLOT_MACHINE
|
||||
""":const:`telegram.constants.DICE_SLOT_MACHINE`"""
|
||||
BOWLING: ClassVar[str] = constants.DICE_BOWLING
|
||||
"""
|
||||
:const:`telegram.constants.DICE_BOWLING`
|
||||
|
||||
.. versionadded:: 13.4
|
||||
"""
|
||||
ALL_EMOJI: ClassVar[List[str]] = constants.DICE_ALL_EMOJI
|
||||
""":const:`telegram.constants.DICE_ALL_EMOJI`"""
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -43,6 +43,7 @@ from .messagequeue import MessageQueue
|
||||
from .messagequeue import DelayQueue
|
||||
from .pollanswerhandler import PollAnswerHandler
|
||||
from .pollhandler import PollHandler
|
||||
from .chatmemberhandler import ChatMemberHandler
|
||||
from .defaults import Defaults
|
||||
|
||||
__all__ = (
|
||||
@@ -78,5 +79,6 @@ __all__ = (
|
||||
'PrefixHandler',
|
||||
'PollAnswerHandler',
|
||||
'PollHandler',
|
||||
'ChatMemberHandler',
|
||||
'Defaults',
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -20,7 +20,7 @@
|
||||
import warnings
|
||||
from abc import ABC, abstractmethod
|
||||
from copy import copy
|
||||
from typing import Any, DefaultDict, Dict, Optional, Tuple, cast, ClassVar
|
||||
from typing import DefaultDict, Dict, Optional, Tuple, cast, ClassVar
|
||||
|
||||
from telegram import Bot
|
||||
|
||||
@@ -31,17 +31,20 @@ class BasePersistence(ABC):
|
||||
"""Interface class for adding persistence to your bot.
|
||||
Subclass this object for different implementations of a persistent bot.
|
||||
|
||||
All relevant methods must be overwritten. This means:
|
||||
All relevant methods must be overwritten. This includes:
|
||||
|
||||
* If :attr:`store_bot_data` is :obj:`True` you must overwrite :meth:`get_bot_data` and
|
||||
:meth:`update_bot_data`.
|
||||
* If :attr:`store_chat_data` is :obj:`True` you must overwrite :meth:`get_chat_data` and
|
||||
:meth:`update_chat_data`.
|
||||
* If :attr:`store_user_data` is :obj:`True` you must overwrite :meth:`get_user_data` and
|
||||
:meth:`update_user_data`.
|
||||
* If you want to store conversation data with :class:`telegram.ext.ConversationHandler`, you
|
||||
must overwrite :meth:`get_conversations` and :meth:`update_conversation`.
|
||||
* :meth:`flush` will be called when the bot is shutdown.
|
||||
* :meth:`get_bot_data`
|
||||
* :meth:`update_bot_data`
|
||||
* :meth:`get_chat_data`
|
||||
* :meth:`update_chat_data`
|
||||
* :meth:`get_user_data`
|
||||
* :meth:`update_user_data`
|
||||
* :meth:`get_conversations`
|
||||
* :meth:`update_conversation`
|
||||
* :meth:`flush`
|
||||
|
||||
If you don't actually need one of those methods, a simple ``pass`` is enough. For example, if
|
||||
``store_bot_data=False``, you don't need :meth:`get_bot_data` and :meth:`update_bot_data`.
|
||||
|
||||
Warning:
|
||||
Persistence will try to replace :class:`telegram.Bot` instances by :attr:`REPLACED_BOT` and
|
||||
@@ -55,14 +58,6 @@ class BasePersistence(ABC):
|
||||
of the :meth:`update/get_*` methods, i.e. you don't need to worry about it while
|
||||
implementing a custom persistence subclass.
|
||||
|
||||
Attributes:
|
||||
store_user_data (:obj:`bool`): Optional, Whether user_data should be saved by this
|
||||
persistence class.
|
||||
store_chat_data (:obj:`bool`): Optional. Whether chat_data should be saved by this
|
||||
persistence class.
|
||||
store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this
|
||||
persistence class.
|
||||
|
||||
Args:
|
||||
store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this
|
||||
persistence class. Default is :obj:`True`.
|
||||
@@ -70,9 +65,19 @@ class BasePersistence(ABC):
|
||||
persistence class. Default is :obj:`True` .
|
||||
store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this
|
||||
persistence class. Default is :obj:`True` .
|
||||
|
||||
Attributes:
|
||||
store_user_data (:obj:`bool`): Optional, Whether user_data should be saved by this
|
||||
persistence class.
|
||||
store_chat_data (:obj:`bool`): Optional. Whether chat_data should be saved by this
|
||||
persistence class.
|
||||
store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this
|
||||
persistence class.
|
||||
"""
|
||||
|
||||
def __new__(cls, *args: Any, **kwargs: Any) -> 'BasePersistence': # pylint: disable=W0613
|
||||
def __new__(
|
||||
cls, *args: object, **kwargs: object # pylint: disable=W0613
|
||||
) -> 'BasePersistence':
|
||||
instance = super().__new__(cls)
|
||||
get_user_data = instance.get_user_data
|
||||
get_chat_data = instance.get_chat_data
|
||||
@@ -81,13 +86,13 @@ class BasePersistence(ABC):
|
||||
update_chat_data = instance.update_chat_data
|
||||
update_bot_data = instance.update_bot_data
|
||||
|
||||
def get_user_data_insert_bot() -> DefaultDict[int, Dict[Any, Any]]:
|
||||
def get_user_data_insert_bot() -> DefaultDict[int, Dict[object, object]]:
|
||||
return instance.insert_bot(get_user_data())
|
||||
|
||||
def get_chat_data_insert_bot() -> DefaultDict[int, Dict[Any, Any]]:
|
||||
def get_chat_data_insert_bot() -> DefaultDict[int, Dict[object, object]]:
|
||||
return instance.insert_bot(get_chat_data())
|
||||
|
||||
def get_bot_data_insert_bot() -> Dict[Any, Any]:
|
||||
def get_bot_data_insert_bot() -> Dict[object, object]:
|
||||
return instance.insert_bot(get_bot_data())
|
||||
|
||||
def update_user_data_replace_bot(user_id: int, data: Dict) -> None:
|
||||
@@ -143,7 +148,7 @@ class BasePersistence(ABC):
|
||||
return cls._replace_bot(obj, {})
|
||||
|
||||
@classmethod
|
||||
def _replace_bot(cls, obj: object, memo: Dict[int, Any]) -> object: # pylint: disable=R0911
|
||||
def _replace_bot(cls, obj: object, memo: Dict[int, object]) -> object: # pylint: disable=R0911
|
||||
obj_id = id(obj)
|
||||
if obj_id in memo:
|
||||
return memo[obj_id]
|
||||
@@ -220,7 +225,7 @@ class BasePersistence(ABC):
|
||||
"""
|
||||
return self._insert_bot(obj, {})
|
||||
|
||||
def _insert_bot(self, obj: object, memo: Dict[int, Any]) -> object: # pylint: disable=R0911
|
||||
def _insert_bot(self, obj: object, memo: Dict[int, object]) -> object: # pylint: disable=R0911
|
||||
obj_id = id(obj)
|
||||
if obj_id in memo:
|
||||
return memo[obj_id]
|
||||
@@ -285,9 +290,9 @@ class BasePersistence(ABC):
|
||||
return obj
|
||||
|
||||
@abstractmethod
|
||||
def get_user_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||
""" "Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
||||
persistence object. It should return the user_data if stored, or an empty
|
||||
def get_user_data(self) -> DefaultDict[int, Dict[object, object]]:
|
||||
"""Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
||||
persistence object. It should return the ``user_data`` if stored, or an empty
|
||||
``defaultdict(dict)``.
|
||||
|
||||
Returns:
|
||||
@@ -295,9 +300,9 @@ class BasePersistence(ABC):
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def get_chat_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||
""" "Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
||||
persistence object. It should return the chat_data if stored, or an empty
|
||||
def get_chat_data(self) -> DefaultDict[int, Dict[object, object]]:
|
||||
"""Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
||||
persistence object. It should return the ``chat_data`` if stored, or an empty
|
||||
``defaultdict(dict)``.
|
||||
|
||||
Returns:
|
||||
@@ -305,9 +310,9 @@ class BasePersistence(ABC):
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def get_bot_data(self) -> Dict[Any, Any]:
|
||||
""" "Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
||||
persistence object. It should return the bot_data if stored, or an empty
|
||||
def get_bot_data(self) -> Dict[object, object]:
|
||||
"""Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
||||
persistence object. It should return the ``bot_data`` if stored, or an empty
|
||||
:obj:`dict`.
|
||||
|
||||
Returns:
|
||||
@@ -316,7 +321,7 @@ class BasePersistence(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def get_conversations(self, name: str) -> ConversationDict:
|
||||
""" "Will be called by :class:`telegram.ext.Dispatcher` when a
|
||||
"""Will be called by :class:`telegram.ext.Dispatcher` when a
|
||||
:class:`telegram.ext.ConversationHandler` is added if
|
||||
:attr:`telegram.ext.ConversationHandler.persistent` is :obj:`True`.
|
||||
It should return the conversations for the handler with `name` or an empty :obj:`dict`
|
||||
@@ -372,8 +377,7 @@ class BasePersistence(ABC):
|
||||
|
||||
def flush(self) -> None:
|
||||
"""Will be called by :class:`telegram.ext.Updater` upon receiving a stop signal. Gives the
|
||||
persistence a chance to finish up saving or close a database connection gracefully. If this
|
||||
is not of any importance just pass will be sufficient.
|
||||
persistence a chance to finish up saving or close a database connection gracefully.
|
||||
"""
|
||||
|
||||
REPLACED_BOT: ClassVar[str] = 'bot_instance_replaced_by_ptb_persistence'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -19,7 +19,7 @@
|
||||
# pylint: disable=R0201
|
||||
"""This module contains the CallbackContext class."""
|
||||
from queue import Queue
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Match, NoReturn, Optional, Tuple, Union
|
||||
from typing import TYPE_CHECKING, Dict, List, Match, NoReturn, Optional, Tuple, Union
|
||||
|
||||
from telegram import Update
|
||||
|
||||
@@ -73,9 +73,8 @@ class CallbackContext:
|
||||
is handled by :class:`telegram.ext.CommandHandler`, :class:`telegram.ext.PrefixHandler`
|
||||
or :class:`telegram.ext.StringCommandHandler`. It contains a list of the words in the
|
||||
text after the command, using any whitespace string as a delimiter.
|
||||
error (:class:`telegram.TelegramError`): Optional. The error that was raised.
|
||||
Only present when passed to a error handler registered with
|
||||
:attr:`telegram.ext.Dispatcher.add_error_handler`.
|
||||
error (:obj:`Exception`): Optional. The error that was raised. Only present when passed
|
||||
to a error handler registered with :attr:`telegram.ext.Dispatcher.add_error_handler`.
|
||||
async_args (List[:obj:`object`]): Optional. Positional arguments of the function that
|
||||
raised the error. Only present when the raising function was run asynchronously using
|
||||
:meth:`telegram.ext.Dispatcher.run_async`.
|
||||
@@ -98,14 +97,14 @@ class CallbackContext:
|
||||
)
|
||||
self._dispatcher = dispatcher
|
||||
self._bot_data = dispatcher.bot_data
|
||||
self._chat_data: Optional[Dict[Any, Any]] = None
|
||||
self._user_data: Optional[Dict[Any, Any]] = None
|
||||
self._chat_data: Optional[Dict[object, object]] = None
|
||||
self._user_data: Optional[Dict[object, object]] = None
|
||||
self.args: Optional[List[str]] = None
|
||||
self.matches: Optional[List[Match]] = None
|
||||
self.error: Optional[Exception] = None
|
||||
self.job: Optional['Job'] = None
|
||||
self.async_args: Optional[Union[List, Tuple]] = None
|
||||
self.async_kwargs: Optional[Dict[str, Any]] = None
|
||||
self.async_kwargs: Optional[Dict[str, object]] = None
|
||||
|
||||
@property
|
||||
def dispatcher(self) -> 'Dispatcher':
|
||||
@@ -117,9 +116,9 @@ class CallbackContext:
|
||||
return self._bot_data
|
||||
|
||||
@bot_data.setter
|
||||
def bot_data(self, value: Any) -> NoReturn:
|
||||
def bot_data(self, value: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to bot_data, see " "https://git.io/fjxKe"
|
||||
"You can not assign a new value to bot_data, see https://git.io/Jt6ic"
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -127,9 +126,9 @@ class CallbackContext:
|
||||
return self._chat_data
|
||||
|
||||
@chat_data.setter
|
||||
def chat_data(self, value: Any) -> NoReturn:
|
||||
def chat_data(self, value: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to chat_data, see " "https://git.io/fjxKe"
|
||||
"You can not assign a new value to chat_data, see https://git.io/Jt6ic"
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -137,9 +136,9 @@ class CallbackContext:
|
||||
return self._user_data
|
||||
|
||||
@user_data.setter
|
||||
def user_data(self, value: Any) -> NoReturn:
|
||||
def user_data(self, value: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to user_data, see " "https://git.io/fjxKe"
|
||||
"You can not assign a new value to user_data, see https://git.io/Jt6ic"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@@ -149,7 +148,7 @@ class CallbackContext:
|
||||
error: Exception,
|
||||
dispatcher: 'Dispatcher',
|
||||
async_args: Union[List, Tuple] = None,
|
||||
async_kwargs: Dict[str, Any] = None,
|
||||
async_kwargs: Dict[str, object] = None,
|
||||
) -> 'CallbackContext':
|
||||
self = cls.from_update(update, dispatcher)
|
||||
self.error = error
|
||||
@@ -177,7 +176,7 @@ class CallbackContext:
|
||||
self.job = job
|
||||
return self
|
||||
|
||||
def update(self, data: Dict[str, Any]) -> None:
|
||||
def update(self, data: Dict[str, object]) -> None:
|
||||
self.__dict__.update(data)
|
||||
|
||||
@property
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -21,7 +21,6 @@
|
||||
import re
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Callable,
|
||||
Dict,
|
||||
Match,
|
||||
@@ -33,7 +32,6 @@ from typing import (
|
||||
)
|
||||
|
||||
from telegram import Update
|
||||
from telegram.utils.types import HandlerArg
|
||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||
|
||||
from .handler import Handler
|
||||
@@ -44,29 +42,11 @@ if TYPE_CHECKING:
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class CallbackQueryHandler(Handler):
|
||||
class CallbackQueryHandler(Handler[Update]):
|
||||
"""Handler class to handle Telegram callback queries. Optionally based on a regex.
|
||||
|
||||
Read the documentation of the ``re`` module for more information.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pattern (:obj:`str` | `Pattern`): Optional. Regex pattern to test
|
||||
:attr:`telegram.CallbackQuery.data` against.
|
||||
pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the
|
||||
callback function.
|
||||
pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
@@ -119,11 +99,29 @@ class CallbackQueryHandler(Handler):
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pattern (:obj:`str` | `Pattern`): Optional. Regex pattern to test
|
||||
:attr:`telegram.CallbackQuery.data` against.
|
||||
pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the
|
||||
callback function.
|
||||
pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
callback: Callable[[Update, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pattern: Union[str, Pattern] = None,
|
||||
@@ -149,11 +147,11 @@ class CallbackQueryHandler(Handler):
|
||||
self.pass_groups = pass_groups
|
||||
self.pass_groupdict = pass_groupdict
|
||||
|
||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, object]]:
|
||||
def check_update(self, update: object) -> Optional[Union[bool, object]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
@@ -172,9 +170,9 @@ class CallbackQueryHandler(Handler):
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
update: Update = None,
|
||||
check_result: Union[bool, Match] = None,
|
||||
) -> Dict[str, Any]:
|
||||
) -> Dict[str, object]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pattern:
|
||||
check_result = cast(Match, check_result)
|
||||
@@ -187,7 +185,7 @@ class CallbackQueryHandler(Handler):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
update: Update,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Union[bool, Match],
|
||||
) -> None:
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2019-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the ChatMemberHandler classes."""
|
||||
from typing import ClassVar, TypeVar, Union, Callable, TYPE_CHECKING
|
||||
|
||||
from telegram import Update
|
||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||
from .handler import Handler
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class ChatMemberHandler(Handler[Update]):
|
||||
"""Handler class to handle Telegram updates that contain a chat member update.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
either the user or the chat that the update was sent in. For each update from the same user
|
||||
or in the same chat, it will be the same ``dict``.
|
||||
|
||||
Note that this is DEPRECATED, and you should use context based callbacks. See
|
||||
https://git.io/fxJuV for more info.
|
||||
|
||||
Warning:
|
||||
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
|
||||
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
|
||||
|
||||
Args:
|
||||
callback (:obj:`callable`): The callback function for this handler. Will be called when
|
||||
:attr:`check_update` has determined that an update should be processed by this handler.
|
||||
Callback signature for context based API:
|
||||
|
||||
``def callback(update: Update, context: CallbackContext)``
|
||||
|
||||
The return value of the callback is usually ignored except for the special case of
|
||||
:class:`telegram.ext.ConversationHandler`.
|
||||
chat_member_types (:obj:`int`, optional): Pass one of :attr:`MY_CHAT_MEMBER`,
|
||||
:attr:`CHAT_MEMBER` or :attr:`ANY_CHAT_MEMBER` to specify if this handler should handle
|
||||
only updates with :attr:`telegram.Update.my_chat_member`,
|
||||
:attr:`telegram.Update.chat_member` or both. Defaults to :attr:`MY_CHAT_MEMBER`.
|
||||
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
|
||||
``update_queue`` will be passed to the callback function. It will be the ``Queue``
|
||||
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
|
||||
that contains new updates which can be used to insert updates. Default is :obj:`False`.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
|
||||
``job_queue`` will be passed to the callback function. It will be a
|
||||
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
|
||||
which can be used to schedule new jobs. Default is :obj:`False`.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
|
||||
``user_data`` will be passed to the callback function. Default is :obj:`False`.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
|
||||
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
chat_member_types (:obj:`int`, optional): Specifies if this handler should handle
|
||||
only updates with :attr:`telegram.Update.my_chat_member`,
|
||||
:attr:`telegram.Update.chat_member` or both.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
MY_CHAT_MEMBER: ClassVar[int] = -1
|
||||
""":obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`."""
|
||||
CHAT_MEMBER: ClassVar[int] = 0
|
||||
""":obj:`int`: Used as a constant to handle only :attr:`telegram.Update.chat_member`."""
|
||||
ANY_CHAT_MEMBER: ClassVar[int] = 1
|
||||
""":obj:`int`: Used as a constant to handle bot :attr:`telegram.Update.my_chat_member`
|
||||
and :attr:`telegram.Update.chat_member`."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callback: Callable[[Update, 'CallbackContext'], RT],
|
||||
chat_member_types: int = MY_CHAT_MEMBER,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
|
||||
):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
pass_job_queue=pass_job_queue,
|
||||
pass_user_data=pass_user_data,
|
||||
pass_chat_data=pass_chat_data,
|
||||
run_async=run_async,
|
||||
)
|
||||
|
||||
self.chat_member_types = chat_member_types
|
||||
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
"""
|
||||
if isinstance(update, Update):
|
||||
if not (update.my_chat_member or update.chat_member):
|
||||
return False
|
||||
if self.chat_member_types == self.ANY_CHAT_MEMBER:
|
||||
return True
|
||||
if self.chat_member_types == self.CHAT_MEMBER:
|
||||
return bool(update.chat_member)
|
||||
return bool(update.my_chat_member)
|
||||
return False
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -21,28 +21,15 @@
|
||||
from typing import Optional, TypeVar, Union
|
||||
|
||||
from telegram import Update
|
||||
from telegram.utils.types import HandlerArg
|
||||
|
||||
from .handler import Handler
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class ChosenInlineResultHandler(Handler):
|
||||
class ChosenInlineResultHandler(Handler[Update]):
|
||||
"""Handler class to handle Telegram updates that contain a chosen inline result.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
@@ -84,13 +71,25 @@ class ChosenInlineResultHandler(Handler):
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, object]]:
|
||||
def check_update(self, update: object) -> Optional[Union[bool, object]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -19,12 +19,12 @@
|
||||
"""This module contains the CommandHandler and PrefixHandler classes."""
|
||||
import re
|
||||
import warnings
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, TypeVar, Union
|
||||
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Tuple, TypeVar, Union
|
||||
|
||||
from telegram import MessageEntity, Update
|
||||
from telegram.ext import BaseFilter, Filters
|
||||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
||||
from telegram.utils.types import HandlerArg, SLT
|
||||
from telegram.utils.types import SLT
|
||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||
|
||||
from .handler import Handler
|
||||
@@ -35,7 +35,7 @@ if TYPE_CHECKING:
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class CommandHandler(Handler):
|
||||
class CommandHandler(Handler[Update]):
|
||||
"""Handler class to handle Telegram commands.
|
||||
|
||||
Commands are Telegram messages that start with ``/``, optionally followed by an ``@`` and the
|
||||
@@ -49,27 +49,6 @@ class CommandHandler(Handler):
|
||||
Note:
|
||||
:class:`telegram.ext.CommandHandler` does *not* handle (edited) channel posts.
|
||||
|
||||
Attributes:
|
||||
command (:class:`telegram.utils.types.SLT[str]`):
|
||||
The command or list of commands this handler should listen for.
|
||||
Limitations are the same as described here https://core.telegram.org/bots#commands
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these
|
||||
Filters.
|
||||
allow_edited (:obj:`bool`): Determines whether the handler should also accept
|
||||
edited messages.
|
||||
pass_args (:obj:`bool`): Determines whether the handler should be passed
|
||||
``args``.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a :obj:`dict` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
@@ -129,12 +108,33 @@ class CommandHandler(Handler):
|
||||
|
||||
Raises:
|
||||
ValueError - when command is too long or has illegal chars.
|
||||
|
||||
Attributes:
|
||||
command (:class:`telegram.utils.types.SLT[str]`):
|
||||
The command or list of commands this handler should listen for.
|
||||
Limitations are the same as described here https://core.telegram.org/bots#commands
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these
|
||||
Filters.
|
||||
allow_edited (:obj:`bool`): Determines whether the handler should also accept
|
||||
edited messages.
|
||||
pass_args (:obj:`bool`): Determines whether the handler should be passed
|
||||
``args``.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
command: SLT[str],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
callback: Callable[[Update, 'CallbackContext'], RT],
|
||||
filters: BaseFilter = None,
|
||||
allow_edited: bool = None,
|
||||
pass_args: bool = False,
|
||||
@@ -177,12 +177,12 @@ class CommandHandler(Handler):
|
||||
self.pass_args = pass_args
|
||||
|
||||
def check_update(
|
||||
self, update: HandlerArg
|
||||
self, update: object
|
||||
) -> Optional[Union[bool, Tuple[List[str], Optional[Union[bool, Dict]]]]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`list`: The list of args for the handler.
|
||||
@@ -218,9 +218,9 @@ class CommandHandler(Handler):
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
update: Update = None,
|
||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
) -> Dict[str, object]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update)
|
||||
if self.pass_args and isinstance(check_result, tuple):
|
||||
optional_args['args'] = check_result[0]
|
||||
@@ -229,7 +229,7 @@ class CommandHandler(Handler):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
update: Update,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]],
|
||||
) -> None:
|
||||
@@ -344,7 +344,7 @@ class PrefixHandler(CommandHandler):
|
||||
self,
|
||||
prefix: SLT[str],
|
||||
command: SLT[str],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
callback: Callable[[Update, 'CallbackContext'], RT],
|
||||
filters: BaseFilter = None,
|
||||
pass_args: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
@@ -415,12 +415,12 @@ class PrefixHandler(CommandHandler):
|
||||
self._commands = [x.lower() + y.lower() for x in self.prefix for y in self.command]
|
||||
|
||||
def check_update(
|
||||
self, update: HandlerArg
|
||||
self, update: object
|
||||
) -> Optional[Union[bool, Tuple[List[str], Optional[Union[bool, Dict]]]]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`list`: The list of args for the handler.
|
||||
@@ -442,7 +442,7 @@ class PrefixHandler(CommandHandler):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
update: Update,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]],
|
||||
) -> None:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -22,7 +22,7 @@
|
||||
import logging
|
||||
import warnings
|
||||
from threading import Lock
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, NoReturn, Optional, Tuple, cast, ClassVar
|
||||
from typing import TYPE_CHECKING, Dict, List, NoReturn, Optional, Tuple, cast, ClassVar
|
||||
|
||||
from telegram import Update
|
||||
from telegram.ext import (
|
||||
@@ -34,8 +34,8 @@ from telegram.ext import (
|
||||
Handler,
|
||||
InlineQueryHandler,
|
||||
)
|
||||
from telegram.utils.promise import Promise
|
||||
from telegram.utils.types import ConversationDict, HandlerArg
|
||||
from telegram.ext.utils.promise import Promise
|
||||
from telegram.utils.types import ConversationDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import Dispatcher, Job
|
||||
@@ -56,10 +56,24 @@ class _ConversationTimeoutContext:
|
||||
self.callback_context = callback_context
|
||||
|
||||
|
||||
class ConversationHandler(Handler):
|
||||
class ConversationHandler(Handler[Update]):
|
||||
"""
|
||||
A handler to hold a conversation with a single user by managing four collections of other
|
||||
handlers.
|
||||
A handler to hold a conversation with a single or multiple users through Telegram updates by
|
||||
managing four collections of other handlers.
|
||||
|
||||
Note:
|
||||
``ConversationHandler`` will only accept updates that are (subclass-)instances of
|
||||
:class:`telegram.Update`. This is, because depending on the :attr:`per_user` and
|
||||
:attr:`per_chat` ``ConversationHandler`` relies on
|
||||
:attr:`telegram.Update.effective_user` and/or :attr:`telegram.Update.effective_chat` in
|
||||
order to determine which conversation an update should belong to. For ``per_message=True``,
|
||||
``ConversationHandler`` uses ``update.callback_query.message.message_id`` when
|
||||
``per_chat=True`` and ``update.callback_query.inline_message_id`` when ``per_chat=False``.
|
||||
For a more detailed explanation, please see our `FAQ`_.
|
||||
|
||||
Finally, ``ConversationHandler``, does *not* handle (edited) channel posts.
|
||||
|
||||
.. _`FAQ`: https://git.io/JtcyU
|
||||
|
||||
The first collection, a ``list`` named :attr:`entry_points`, is used to initiate the
|
||||
conversation, for example with a :class:`telegram.ext.CommandHandler` or
|
||||
@@ -101,35 +115,6 @@ class ConversationHandler(Handler):
|
||||
|
||||
.. _`examples`: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples
|
||||
|
||||
Attributes:
|
||||
entry_points (List[:class:`telegram.ext.Handler`]): A list of ``Handler`` objects that can
|
||||
trigger the start of the conversation.
|
||||
states (Dict[:obj:`object`, List[:class:`telegram.ext.Handler`]]): A :obj:`dict` that
|
||||
defines the different states of conversation a user can be in and one or more
|
||||
associated ``Handler`` objects that should be used in that state.
|
||||
fallbacks (List[:class:`telegram.ext.Handler`]): A list of handlers that might be used if
|
||||
the user is in a conversation, but every handler for their current state returned
|
||||
:obj:`False` on :attr:`check_update`.
|
||||
allow_reentry (:obj:`bool`): Determines if a user can restart a conversation with
|
||||
an entry point.
|
||||
per_chat (:obj:`bool`): If the conversationkey should contain the Chat's ID.
|
||||
per_user (:obj:`bool`): If the conversationkey should contain the User's ID.
|
||||
per_message (:obj:`bool`): If the conversationkey should contain the Message's
|
||||
ID.
|
||||
conversation_timeout (:obj:`float` | :obj:`datetime.timedelta`): Optional. When this
|
||||
handler is inactive more than this timeout (in seconds), it will be automatically
|
||||
ended. If this value is 0 (default), there will be no timeout. When it's triggered, the
|
||||
last received update and the corresponding ``context`` will be handled by ALL the
|
||||
handler's who's :attr:`check_update` method returns :obj:`True` that are in the state
|
||||
:attr:`ConversationHandler.TIMEOUT`.
|
||||
name (:obj:`str`): Optional. The name for this conversationhandler. Required for
|
||||
persistence
|
||||
persistent (:obj:`bool`): Optional. If the conversations dict for this handler should be
|
||||
saved. Name is required and persistence has to be set in :class:`telegram.ext.Updater`
|
||||
map_to_parent (Dict[:obj:`object`, :obj:`object`]): Optional. A :obj:`dict` that can be
|
||||
used to instruct a nested conversationhandler to transition into a mapped state on
|
||||
its parent conversationhandler in place of a specified nested state.
|
||||
|
||||
Args:
|
||||
entry_points (List[:class:`telegram.ext.Handler`]): A list of ``Handler`` objects that can
|
||||
trigger the start of the conversation. The first handler which :attr:`check_update`
|
||||
@@ -165,10 +150,52 @@ class ConversationHandler(Handler):
|
||||
map_to_parent (Dict[:obj:`object`, :obj:`object`], optional): A :obj:`dict` that can be
|
||||
used to instruct a nested conversationhandler to transition into a mapped state on
|
||||
its parent conversationhandler in place of a specified nested state.
|
||||
run_async (:obj:`bool`, optional): Pass :obj:`True` to *override* the
|
||||
:attr:`Handler.run_async` setting of all handlers (in :attr:`entry_points`,
|
||||
:attr:`states` and :attr:`fallbacks`).
|
||||
|
||||
Note:
|
||||
If set to :obj:`True`, you should not pass a handler instance, that needs to be
|
||||
run synchronously in another context.
|
||||
|
||||
.. versionadded:: 13.2
|
||||
|
||||
Raises:
|
||||
ValueError
|
||||
|
||||
Attributes:
|
||||
entry_points (List[:class:`telegram.ext.Handler`]): A list of ``Handler`` objects that can
|
||||
trigger the start of the conversation.
|
||||
states (Dict[:obj:`object`, List[:class:`telegram.ext.Handler`]]): A :obj:`dict` that
|
||||
defines the different states of conversation a user can be in and one or more
|
||||
associated ``Handler`` objects that should be used in that state.
|
||||
fallbacks (List[:class:`telegram.ext.Handler`]): A list of handlers that might be used if
|
||||
the user is in a conversation, but every handler for their current state returned
|
||||
:obj:`False` on :attr:`check_update`.
|
||||
allow_reentry (:obj:`bool`): Determines if a user can restart a conversation with
|
||||
an entry point.
|
||||
per_chat (:obj:`bool`): If the conversationkey should contain the Chat's ID.
|
||||
per_user (:obj:`bool`): If the conversationkey should contain the User's ID.
|
||||
per_message (:obj:`bool`): If the conversationkey should contain the Message's
|
||||
ID.
|
||||
conversation_timeout (:obj:`float` | :obj:`datetime.timedelta`): Optional. When this
|
||||
handler is inactive more than this timeout (in seconds), it will be automatically
|
||||
ended. If this value is 0 (default), there will be no timeout. When it's triggered, the
|
||||
last received update and the corresponding ``context`` will be handled by ALL the
|
||||
handler's who's :attr:`check_update` method returns :obj:`True` that are in the state
|
||||
:attr:`ConversationHandler.TIMEOUT`.
|
||||
name (:obj:`str`): Optional. The name for this conversationhandler. Required for
|
||||
persistence
|
||||
persistent (:obj:`bool`): Optional. If the conversations dict for this handler should be
|
||||
saved. Name is required and persistence has to be set in :class:`telegram.ext.Updater`
|
||||
map_to_parent (Dict[:obj:`object`, :obj:`object`]): Optional. A :obj:`dict` that can be
|
||||
used to instruct a nested conversationhandler to transition into a mapped state on
|
||||
its parent conversationhandler in place of a specified nested state.
|
||||
run_async (:obj:`bool`): If :obj:`True`, will override the
|
||||
:attr:`Handler.run_async` setting of all internal handlers on initialization.
|
||||
|
||||
.. versionadded:: 13.2
|
||||
|
||||
"""
|
||||
|
||||
END: ClassVar[int] = -1
|
||||
@@ -192,8 +219,9 @@ class ConversationHandler(Handler):
|
||||
name: str = None,
|
||||
persistent: bool = False,
|
||||
map_to_parent: Dict[object, object] = None,
|
||||
run_async: bool = False,
|
||||
):
|
||||
self.run_async = False
|
||||
self.run_async = run_async
|
||||
|
||||
self._entry_points = entry_points
|
||||
self._states = states
|
||||
@@ -229,7 +257,7 @@ class ConversationHandler(Handler):
|
||||
"since message IDs are not globally unique."
|
||||
)
|
||||
|
||||
all_handlers = list()
|
||||
all_handlers: List[Handler] = list()
|
||||
all_handlers.extend(entry_points)
|
||||
all_handlers.extend(fallbacks)
|
||||
|
||||
@@ -263,12 +291,16 @@ class ConversationHandler(Handler):
|
||||
)
|
||||
break
|
||||
|
||||
if self.run_async:
|
||||
for handler in all_handlers:
|
||||
handler.run_async = True
|
||||
|
||||
@property
|
||||
def entry_points(self) -> List[Handler]:
|
||||
return self._entry_points
|
||||
|
||||
@entry_points.setter
|
||||
def entry_points(self, value: Any) -> NoReturn:
|
||||
def entry_points(self, value: object) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to entry_points after initialization.')
|
||||
|
||||
@property
|
||||
@@ -276,7 +308,7 @@ class ConversationHandler(Handler):
|
||||
return self._states
|
||||
|
||||
@states.setter
|
||||
def states(self, value: Any) -> NoReturn:
|
||||
def states(self, value: object) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to states after initialization.')
|
||||
|
||||
@property
|
||||
@@ -284,7 +316,7 @@ class ConversationHandler(Handler):
|
||||
return self._fallbacks
|
||||
|
||||
@fallbacks.setter
|
||||
def fallbacks(self, value: Any) -> NoReturn:
|
||||
def fallbacks(self, value: object) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to fallbacks after initialization.')
|
||||
|
||||
@property
|
||||
@@ -292,7 +324,7 @@ class ConversationHandler(Handler):
|
||||
return self._allow_reentry
|
||||
|
||||
@allow_reentry.setter
|
||||
def allow_reentry(self, value: Any) -> NoReturn:
|
||||
def allow_reentry(self, value: object) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to allow_reentry after initialization.')
|
||||
|
||||
@property
|
||||
@@ -300,7 +332,7 @@ class ConversationHandler(Handler):
|
||||
return self._per_user
|
||||
|
||||
@per_user.setter
|
||||
def per_user(self, value: Any) -> NoReturn:
|
||||
def per_user(self, value: object) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to per_user after initialization.')
|
||||
|
||||
@property
|
||||
@@ -308,7 +340,7 @@ class ConversationHandler(Handler):
|
||||
return self._per_chat
|
||||
|
||||
@per_chat.setter
|
||||
def per_chat(self, value: Any) -> NoReturn:
|
||||
def per_chat(self, value: object) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to per_chat after initialization.')
|
||||
|
||||
@property
|
||||
@@ -316,7 +348,7 @@ class ConversationHandler(Handler):
|
||||
return self._per_message
|
||||
|
||||
@per_message.setter
|
||||
def per_message(self, value: Any) -> NoReturn:
|
||||
def per_message(self, value: object) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to per_message after initialization.')
|
||||
|
||||
@property
|
||||
@@ -324,7 +356,7 @@ class ConversationHandler(Handler):
|
||||
return self._conversation_timeout
|
||||
|
||||
@conversation_timeout.setter
|
||||
def conversation_timeout(self, value: Any) -> NoReturn:
|
||||
def conversation_timeout(self, value: object) -> NoReturn:
|
||||
raise ValueError(
|
||||
'You can not assign a new value to conversation_timeout after ' 'initialization.'
|
||||
)
|
||||
@@ -334,7 +366,7 @@ class ConversationHandler(Handler):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, value: Any) -> NoReturn:
|
||||
def name(self, value: object) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to name after initialization.')
|
||||
|
||||
@property
|
||||
@@ -342,7 +374,7 @@ class ConversationHandler(Handler):
|
||||
return self._map_to_parent
|
||||
|
||||
@map_to_parent.setter
|
||||
def map_to_parent(self, value: Any) -> NoReturn:
|
||||
def map_to_parent(self, value: object) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to map_to_parent after initialization.')
|
||||
|
||||
@property
|
||||
@@ -391,13 +423,13 @@ class ConversationHandler(Handler):
|
||||
|
||||
return tuple(key)
|
||||
|
||||
def check_update(self, update: HandlerArg) -> CheckUpdateType: # pylint: disable=R0911
|
||||
def check_update(self, update: object) -> CheckUpdateType: # pylint: disable=R0911
|
||||
"""
|
||||
Determines whether an update should be handled by this conversationhandler, and if so in
|
||||
which state the conversation currently is.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
@@ -406,7 +438,7 @@ class ConversationHandler(Handler):
|
||||
if not isinstance(update, Update):
|
||||
return None
|
||||
# Ignore messages in channels
|
||||
if update.channel_post:
|
||||
if update.channel_post or update.edited_channel_post:
|
||||
return None
|
||||
if self.per_chat and not update.effective_chat:
|
||||
return None
|
||||
@@ -487,7 +519,7 @@ class ConversationHandler(Handler):
|
||||
|
||||
def handle_update( # type: ignore[override]
|
||||
self,
|
||||
update: HandlerArg,
|
||||
update: Update,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: CheckUpdateType,
|
||||
context: CallbackContext = None,
|
||||
|
||||
+73
-36
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2020
|
||||
# Copyright (C) 2020-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -16,39 +16,19 @@
|
||||
#
|
||||
# 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=R0201, E0401
|
||||
# pylint: disable=R0201
|
||||
"""This module contains the class Defaults, which allows to pass default values to Updater."""
|
||||
from typing import Any, NoReturn, Optional, Union
|
||||
from typing import NoReturn, Optional, Dict, Any
|
||||
|
||||
import pytz
|
||||
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.types import ODVInput
|
||||
|
||||
|
||||
class Defaults:
|
||||
"""Convenience Class to gather all parameters with a (user defined) default value
|
||||
|
||||
Attributes:
|
||||
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or URLs in your bot's message.
|
||||
disable_notification (:obj:`bool`): Optional. Sends the message silently. Users will
|
||||
receive a notification with no sound.
|
||||
disable_web_page_preview (:obj:`bool`): Optional. Disables link previews for links in this
|
||||
message.
|
||||
allow_sending_without_reply (:obj:`bool`): Optional. Pass :obj:`True`, if the message
|
||||
should be sent even if the specified replied-to message is not found.
|
||||
timeout (:obj:`int` | :obj:`float`): Optional. If this value is specified, use it as the
|
||||
read timeout from the server (instead of the one specified during creation of the
|
||||
connection pool).
|
||||
quote (:obj:`bool`): Optional. If set to :obj:`True`, the reply is sent as an actual reply
|
||||
to the message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will
|
||||
be ignored. Default: :obj:`True` in group chats and :obj:`False` in private chats.
|
||||
tzinfo (:obj:`tzinfo`): A timezone to be used for all date(time) objects appearing
|
||||
throughout PTB.
|
||||
run_async (:obj:`bool`): Optional. Default setting for the ``run_async`` parameter of
|
||||
handlers and error handlers registered through :meth:`Dispatcher.add_handler` and
|
||||
:meth:`Dispatcher.add_error_handler`.
|
||||
|
||||
Parameters:
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or URLs in your bot's message.
|
||||
@@ -68,9 +48,35 @@ class Defaults:
|
||||
appearing throughout PTB, i.e. if a timezone naive date(time) object is passed
|
||||
somewhere, it will be assumed to be in ``tzinfo``. Must be a timezone provided by the
|
||||
``pytz`` module. Defaults to UTC.
|
||||
|
||||
Note:
|
||||
Will *not* be used for :meth:`telegram.Bot.get_updates`!
|
||||
run_async (:obj:`bool`, optional): Default setting for the ``run_async`` parameter of
|
||||
handlers and error handlers registered through :meth:`Dispatcher.add_handler` and
|
||||
:meth:`Dispatcher.add_error_handler`. Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or URLs in your bot's message.
|
||||
explanation_parse_mode (:obj:`str`): Optional. Alias for :attr:`parse_mode`, used for
|
||||
the corresponding parameter of :meth:`telegram.Bot.send_poll`.
|
||||
disable_notification (:obj:`bool`): Optional. Sends the message silently. Users will
|
||||
receive a notification with no sound.
|
||||
disable_web_page_preview (:obj:`bool`): Optional. Disables link previews for links in this
|
||||
message.
|
||||
allow_sending_without_reply (:obj:`bool`): Optional. Pass :obj:`True`, if the message
|
||||
should be sent even if the specified replied-to message is not found.
|
||||
timeout (:obj:`int` | :obj:`float`): Optional. If this value is specified, use it as the
|
||||
read timeout from the server (instead of the one specified during creation of the
|
||||
connection pool).
|
||||
quote (:obj:`bool`): Optional. If set to :obj:`True`, the reply is sent as an actual reply
|
||||
to the message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will
|
||||
be ignored. Default: :obj:`True` in group chats and :obj:`False` in private chats.
|
||||
tzinfo (:obj:`tzinfo`): A timezone to be used for all date(time) objects appearing
|
||||
throughout PTB.
|
||||
run_async (:obj:`bool`): Optional. Default setting for the ``run_async`` parameter of
|
||||
handlers and error handlers registered through :meth:`Dispatcher.add_handler` and
|
||||
:meth:`Dispatcher.add_error_handler`.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -80,7 +86,7 @@ class Defaults:
|
||||
disable_web_page_preview: bool = None,
|
||||
# Timeout needs special treatment, since the bot methods have two different
|
||||
# default values for timeout (None and 20s)
|
||||
timeout: Union[float, DefaultValue] = DEFAULT_NONE,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
quote: bool = None,
|
||||
tzinfo: pytz.BaseTzInfo = pytz.utc,
|
||||
run_async: bool = False,
|
||||
@@ -95,12 +101,43 @@ class Defaults:
|
||||
self._tzinfo = tzinfo
|
||||
self._run_async = run_async
|
||||
|
||||
# Gather all defaults that actually have a default value
|
||||
self._api_defaults = {}
|
||||
for kwarg in (
|
||||
'parse_mode',
|
||||
'explanation_parse_mode',
|
||||
'disable_notification',
|
||||
'disable_web_page_preview',
|
||||
'allow_sending_without_reply',
|
||||
):
|
||||
value = getattr(self, kwarg)
|
||||
if value not in [None, DEFAULT_NONE]:
|
||||
self._api_defaults[kwarg] = value
|
||||
# Special casing, as None is a valid default value
|
||||
if self.timeout != DEFAULT_NONE:
|
||||
self._api_defaults['timeout'] = self.timeout
|
||||
|
||||
@property
|
||||
def api_defaults(self) -> Dict[str, Any]:
|
||||
return self._api_defaults
|
||||
|
||||
@property
|
||||
def parse_mode(self) -> Optional[str]:
|
||||
return self._parse_mode
|
||||
|
||||
@parse_mode.setter
|
||||
def parse_mode(self, value: Any) -> NoReturn:
|
||||
def parse_mode(self, value: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
)
|
||||
|
||||
@property
|
||||
def explanation_parse_mode(self) -> Optional[str]:
|
||||
return self._parse_mode
|
||||
|
||||
@explanation_parse_mode.setter
|
||||
def explanation_parse_mode(self, value: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
@@ -111,7 +148,7 @@ class Defaults:
|
||||
return self._disable_notification
|
||||
|
||||
@disable_notification.setter
|
||||
def disable_notification(self, value: Any) -> NoReturn:
|
||||
def disable_notification(self, value: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
@@ -122,7 +159,7 @@ class Defaults:
|
||||
return self._disable_web_page_preview
|
||||
|
||||
@disable_web_page_preview.setter
|
||||
def disable_web_page_preview(self, value: Any) -> NoReturn:
|
||||
def disable_web_page_preview(self, value: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
@@ -133,18 +170,18 @@ class Defaults:
|
||||
return self._allow_sending_without_reply
|
||||
|
||||
@allow_sending_without_reply.setter
|
||||
def allow_sending_without_reply(self, value: Any) -> NoReturn:
|
||||
def allow_sending_without_reply(self, value: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
)
|
||||
|
||||
@property
|
||||
def timeout(self) -> Union[float, DefaultValue]:
|
||||
def timeout(self) -> ODVInput[float]:
|
||||
return self._timeout
|
||||
|
||||
@timeout.setter
|
||||
def timeout(self, value: Any) -> NoReturn:
|
||||
def timeout(self, value: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
@@ -155,7 +192,7 @@ class Defaults:
|
||||
return self._quote
|
||||
|
||||
@quote.setter
|
||||
def quote(self, value: Any) -> NoReturn:
|
||||
def quote(self, value: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
@@ -166,18 +203,18 @@ class Defaults:
|
||||
return self._tzinfo
|
||||
|
||||
@tzinfo.setter
|
||||
def tzinfo(self, value: Any) -> NoReturn:
|
||||
def tzinfo(self, value: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
)
|
||||
|
||||
@property
|
||||
def run_async(self) -> Optional[bool]:
|
||||
def run_async(self) -> bool:
|
||||
return self._run_async
|
||||
|
||||
@run_async.setter
|
||||
def run_async(self, value: Any) -> NoReturn:
|
||||
def run_async(self, value: object) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -19,7 +19,7 @@
|
||||
"""This module contains the DictPersistence class."""
|
||||
from copy import deepcopy
|
||||
|
||||
from typing import Any, DefaultDict, Dict, Optional, Tuple
|
||||
from typing import DefaultDict, Dict, Optional, Tuple
|
||||
from collections import defaultdict
|
||||
|
||||
from telegram.utils.helpers import (
|
||||
@@ -54,14 +54,6 @@ class DictPersistence(BasePersistence):
|
||||
:meth:`telegram.ext.BasePersistence.replace_bot` and
|
||||
:meth:`telegram.ext.BasePersistence.insert_bot`.
|
||||
|
||||
Attributes:
|
||||
store_user_data (:obj:`bool`): Whether user_data should be saved by this
|
||||
persistence class.
|
||||
store_chat_data (:obj:`bool`): Whether chat_data should be saved by this
|
||||
persistence class.
|
||||
store_bot_data (:obj:`bool`): Whether bot_data should be saved by this
|
||||
persistence class.
|
||||
|
||||
Args:
|
||||
store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this
|
||||
persistence class. Default is :obj:`True`.
|
||||
@@ -77,6 +69,14 @@ class DictPersistence(BasePersistence):
|
||||
bot_data on creating this persistence. Default is ``""``.
|
||||
conversations_json (:obj:`str`, optional): Json string that will be used to reconstruct
|
||||
conversation on creating this persistence. Default is ``""``.
|
||||
|
||||
Attributes:
|
||||
store_user_data (:obj:`bool`): Whether user_data should be saved by this
|
||||
persistence class.
|
||||
store_chat_data (:obj:`bool`): Whether chat_data should be saved by this
|
||||
persistence class.
|
||||
store_bot_data (:obj:`bool`): Whether bot_data should be saved by this
|
||||
persistence class.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -169,7 +169,7 @@ class DictPersistence(BasePersistence):
|
||||
return json.dumps(self.bot_data)
|
||||
|
||||
@property
|
||||
def conversations(self) -> Optional[Dict[str, Dict[Tuple, Any]]]:
|
||||
def conversations(self) -> Optional[Dict[str, Dict[Tuple, object]]]:
|
||||
""":obj:`dict`: The conversations as a dict."""
|
||||
return self._conversations
|
||||
|
||||
@@ -180,7 +180,7 @@ class DictPersistence(BasePersistence):
|
||||
return self._conversations_json
|
||||
return encode_conversations_to_json(self.conversations) # type: ignore[arg-type]
|
||||
|
||||
def get_user_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||
def get_user_data(self) -> DefaultDict[int, Dict[object, object]]:
|
||||
"""Returns the user_data created from the ``user_data_json`` or an empty
|
||||
:obj:`defaultdict`.
|
||||
|
||||
@@ -193,7 +193,7 @@ class DictPersistence(BasePersistence):
|
||||
self._user_data = defaultdict(dict)
|
||||
return deepcopy(self.user_data) # type: ignore[arg-type]
|
||||
|
||||
def get_chat_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||
def get_chat_data(self) -> DefaultDict[int, Dict[object, object]]:
|
||||
"""Returns the chat_data created from the ``chat_data_json`` or an empty
|
||||
:obj:`defaultdict`.
|
||||
|
||||
@@ -206,7 +206,7 @@ class DictPersistence(BasePersistence):
|
||||
self._chat_data = defaultdict(dict)
|
||||
return deepcopy(self.chat_data) # type: ignore[arg-type]
|
||||
|
||||
def get_bot_data(self) -> Dict[Any, Any]:
|
||||
def get_bot_data(self) -> Dict[object, object]:
|
||||
"""Returns the bot_data created from the ``bot_data_json`` or an empty :obj:`dict`.
|
||||
|
||||
Returns:
|
||||
|
||||
+61
-45
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -26,7 +26,7 @@ from functools import wraps
|
||||
from queue import Empty, Queue
|
||||
from threading import BoundedSemaphore, Event, Lock, Thread, current_thread
|
||||
from time import sleep
|
||||
from typing import TYPE_CHECKING, Any, Callable, DefaultDict, Dict, List, Optional, Set, Union
|
||||
from typing import TYPE_CHECKING, Callable, DefaultDict, Dict, List, Optional, Set, Union
|
||||
from uuid import uuid4
|
||||
|
||||
from telegram import TelegramError, Update
|
||||
@@ -34,8 +34,7 @@ from telegram.ext import BasePersistence
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.handler import Handler
|
||||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
||||
from telegram.utils.promise import Promise
|
||||
from telegram.utils.types import HandlerArg
|
||||
from telegram.ext.utils.promise import Promise
|
||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -46,8 +45,8 @@ DEFAULT_GROUP: int = 0
|
||||
|
||||
|
||||
def run_async(
|
||||
func: Callable[[Update, CallbackContext], Any]
|
||||
) -> Callable[[Update, CallbackContext], Any]:
|
||||
func: Callable[[Update, CallbackContext], object]
|
||||
) -> Callable[[Update, CallbackContext], object]:
|
||||
"""
|
||||
Function decorator that will run the function in a new thread.
|
||||
|
||||
@@ -65,7 +64,7 @@ def run_async(
|
||||
"""
|
||||
|
||||
@wraps(func)
|
||||
def async_func(*args: Any, **kwargs: Any) -> Any:
|
||||
def async_func(*args: object, **kwargs: object) -> object:
|
||||
warnings.warn(
|
||||
'The @run_async decorator is deprecated. Use the `run_async` parameter of '
|
||||
'your Handler or `Dispatcher.run_async` instead.',
|
||||
@@ -81,7 +80,7 @@ def run_async(
|
||||
|
||||
class DispatcherHandlerStop(Exception):
|
||||
"""
|
||||
Raise this in handler to prevent execution any other handler (even in different group).
|
||||
Raise this in handler to prevent execution of any other handler (even in different group).
|
||||
|
||||
In order to use this exception in a :class:`telegram.ext.ConversationHandler`, pass the
|
||||
optional ``state`` parameter instead of returning the next state:
|
||||
@@ -107,19 +106,6 @@ class DispatcherHandlerStop(Exception):
|
||||
class Dispatcher:
|
||||
"""This class dispatches all kinds of updates to its registered handlers.
|
||||
|
||||
Attributes:
|
||||
bot (:class:`telegram.Bot`): The bot object that should be passed to the handlers.
|
||||
update_queue (:obj:`Queue`): The synchronized queue that will contain the updates.
|
||||
job_queue (:class:`telegram.ext.JobQueue`): Optional. The :class:`telegram.ext.JobQueue`
|
||||
instance to pass onto handler callbacks.
|
||||
workers (:obj:`int`, optional): Number of maximum concurrent worker threads for the
|
||||
``@run_async`` decorator and :meth:`run_async`.
|
||||
user_data (:obj:`defaultdict`): A dictionary handlers can use to store data for the user.
|
||||
chat_data (:obj:`defaultdict`): A dictionary handlers can use to store data for the chat.
|
||||
bot_data (:obj:`dict`): A dictionary handlers can use to store data for the bot.
|
||||
persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to
|
||||
store data that should be persistent over restarts.
|
||||
|
||||
Args:
|
||||
bot (:class:`telegram.Bot`): The bot object that should be passed to the handlers.
|
||||
update_queue (:obj:`Queue`): The synchronized queue that will contain the updates.
|
||||
@@ -133,6 +119,19 @@ class Dispatcher:
|
||||
API (ignored if `dispatcher` argument is used). Defaults to :obj:`True`.
|
||||
**New users**: set this to :obj:`True`.
|
||||
|
||||
Attributes:
|
||||
bot (:class:`telegram.Bot`): The bot object that should be passed to the handlers.
|
||||
update_queue (:obj:`Queue`): The synchronized queue that will contain the updates.
|
||||
job_queue (:class:`telegram.ext.JobQueue`): Optional. The :class:`telegram.ext.JobQueue`
|
||||
instance to pass onto handler callbacks.
|
||||
workers (:obj:`int`, optional): Number of maximum concurrent worker threads for the
|
||||
``@run_async`` decorator and :meth:`run_async`.
|
||||
user_data (:obj:`defaultdict`): A dictionary handlers can use to store data for the user.
|
||||
chat_data (:obj:`defaultdict`): A dictionary handlers can use to store data for the chat.
|
||||
bot_data (:obj:`dict`): A dictionary handlers can use to store data for the bot.
|
||||
persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to
|
||||
store data that should be persistent over restarts.
|
||||
|
||||
"""
|
||||
|
||||
__singleton_lock = Lock()
|
||||
@@ -163,8 +162,8 @@ class Dispatcher:
|
||||
stacklevel=3,
|
||||
)
|
||||
|
||||
self.user_data: DefaultDict[int, Dict[Any, Any]] = defaultdict(dict)
|
||||
self.chat_data: DefaultDict[int, Dict[Any, Any]] = defaultdict(dict)
|
||||
self.user_data: DefaultDict[int, Dict[object, object]] = defaultdict(dict)
|
||||
self.chat_data: DefaultDict[int, Dict[object, object]] = defaultdict(dict)
|
||||
self.bot_data = {}
|
||||
self.persistence: Optional[BasePersistence] = None
|
||||
self._update_persistence_lock = Lock()
|
||||
@@ -288,7 +287,7 @@ class Dispatcher:
|
||||
self.logger.exception('An uncaught error was raised while handling the error.')
|
||||
|
||||
def run_async(
|
||||
self, func: Callable[..., Any], *args: Any, update: HandlerArg = None, **kwargs: Any
|
||||
self, func: Callable[..., object], *args: object, update: object = None, **kwargs: object
|
||||
) -> Promise:
|
||||
"""
|
||||
Queue a function (with given args/kwargs) to be run asynchronously. Exceptions raised
|
||||
@@ -304,9 +303,9 @@ class Dispatcher:
|
||||
Args:
|
||||
func (:obj:`callable`): The function to run in the thread.
|
||||
*args (:obj:`tuple`, optional): Arguments to ``func``.
|
||||
update (:class:`telegram.Update`, optional): The update associated with the functions
|
||||
call. If passed, it will be available in the error handlers, in case an exception
|
||||
is raised by :attr:`func`.
|
||||
update (:class:`telegram.Update` | :obj:`object`, optional): The update associated with
|
||||
the functions call. If passed, it will be available in the error handlers, in case
|
||||
an exception is raised by :attr:`func`.
|
||||
**kwargs (:obj:`dict`, optional): Keyword arguments to ``func``.
|
||||
|
||||
Returns:
|
||||
@@ -317,11 +316,11 @@ class Dispatcher:
|
||||
|
||||
def _run_async(
|
||||
self,
|
||||
func: Callable[..., Any],
|
||||
*args: Any,
|
||||
update: HandlerArg = None,
|
||||
func: Callable[..., object],
|
||||
*args: object,
|
||||
update: object = None,
|
||||
error_handling: bool = True,
|
||||
**kwargs: Any,
|
||||
**kwargs: object,
|
||||
) -> Promise:
|
||||
# TODO: Remove error_handling parameter once we drop the @run_async decorator
|
||||
promise = Promise(func, args, kwargs, update=update, error_handling=error_handling)
|
||||
@@ -403,11 +402,18 @@ class Dispatcher:
|
||||
def has_running_threads(self) -> bool:
|
||||
return self.running or bool(self.__async_threads)
|
||||
|
||||
def process_update(self, update: Union[str, Update, TelegramError]) -> None:
|
||||
"""Processes a single update.
|
||||
def process_update(self, update: object) -> None:
|
||||
"""Processes a single update and updates the persistence.
|
||||
|
||||
Note:
|
||||
If the update is handled by least one synchronously running handlers (i.e.
|
||||
``run_async=False``), :meth:`update_persistence` is called *once* after all handlers
|
||||
synchronous handlers are done. Each asynchronously running handler will trigger
|
||||
:meth:`update_persistence` on its own.
|
||||
|
||||
Args:
|
||||
update (:obj:`str` | :class:`telegram.Update` | :class:`telegram.TelegramError`):
|
||||
update (:class:`telegram.Update` | :obj:`object` | \
|
||||
:class:`telegram.error.TelegramError`):
|
||||
The update to process.
|
||||
|
||||
"""
|
||||
@@ -421,6 +427,8 @@ class Dispatcher:
|
||||
return
|
||||
|
||||
context = None
|
||||
handled = False
|
||||
sync_modes = []
|
||||
|
||||
for group in self.groups:
|
||||
try:
|
||||
@@ -429,11 +437,9 @@ class Dispatcher:
|
||||
if check is not None and check is not False:
|
||||
if not context and self.use_context:
|
||||
context = CallbackContext.from_update(update, self)
|
||||
handled = True
|
||||
sync_modes.append(handler.run_async)
|
||||
handler.handle_update(update, self, check, context)
|
||||
|
||||
# If handler runs async updating immediately doesn't make sense
|
||||
if not handler.run_async:
|
||||
self.update_persistence(update=update)
|
||||
break
|
||||
|
||||
# Stop processing with any other handler.
|
||||
@@ -453,6 +459,16 @@ class Dispatcher:
|
||||
except Exception:
|
||||
self.logger.exception('An uncaught error was raised while handling the error.')
|
||||
|
||||
# Update persistence, if handled
|
||||
handled_only_async = all(sync_modes)
|
||||
if handled:
|
||||
# Respect default settings
|
||||
if all(mode is DEFAULT_FALSE for mode in sync_modes) and self.bot.defaults:
|
||||
handled_only_async = self.bot.defaults.run_async
|
||||
# If update was only handled by async handlers, we don't need to update here
|
||||
if not handled_only_async:
|
||||
self.update_persistence(update=update)
|
||||
|
||||
def add_handler(self, handler: Handler, group: int = DEFAULT_GROUP) -> None:
|
||||
"""Register a handler.
|
||||
|
||||
@@ -515,7 +531,7 @@ class Dispatcher:
|
||||
del self.handlers[group]
|
||||
self.groups.remove(group)
|
||||
|
||||
def update_persistence(self, update: HandlerArg = None) -> None:
|
||||
def update_persistence(self, update: object = None) -> None:
|
||||
"""Update :attr:`user_data`, :attr:`chat_data` and :attr:`bot_data` in :attr:`persistence`.
|
||||
|
||||
Args:
|
||||
@@ -525,7 +541,7 @@ class Dispatcher:
|
||||
with self._update_persistence_lock:
|
||||
self.__update_persistence(update)
|
||||
|
||||
def __update_persistence(self, update: HandlerArg = None) -> None:
|
||||
def __update_persistence(self, update: object = None) -> None:
|
||||
if self.persistence:
|
||||
# We use list() here in order to decouple chat_ids from self.chat_data, as dict view
|
||||
# objects will change, when the dict does and we want to loop over chat_ids
|
||||
@@ -586,7 +602,7 @@ class Dispatcher:
|
||||
|
||||
def add_error_handler(
|
||||
self,
|
||||
callback: Callable[[Any, CallbackContext], None],
|
||||
callback: Callable[[object, CallbackContext], None],
|
||||
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, # pylint: disable=W0621
|
||||
) -> None:
|
||||
"""Registers an error handler in the Dispatcher. This handler will receive every error
|
||||
@@ -603,7 +619,7 @@ class Dispatcher:
|
||||
callback (:obj:`callable`): The callback function for this error handler. Will be
|
||||
called when an error is raised. Callback signature for context based API:
|
||||
|
||||
``def callback(update: Update, context: CallbackContext)``
|
||||
``def callback(update: object, context: CallbackContext)``
|
||||
|
||||
The error that happened will be present in context.error.
|
||||
run_async (:obj:`bool`, optional): Whether this handlers callback should be run
|
||||
@@ -622,7 +638,7 @@ class Dispatcher:
|
||||
|
||||
self.error_handlers[callback] = run_async
|
||||
|
||||
def remove_error_handler(self, callback: Callable[[Any, CallbackContext], None]) -> None:
|
||||
def remove_error_handler(self, callback: Callable[[object, CallbackContext], None]) -> None:
|
||||
"""Removes an error handler.
|
||||
|
||||
Args:
|
||||
@@ -632,12 +648,12 @@ class Dispatcher:
|
||||
self.error_handlers.pop(callback, None)
|
||||
|
||||
def dispatch_error(
|
||||
self, update: Optional[HandlerArg], error: Exception, promise: Promise = None
|
||||
self, update: Optional[object], error: Exception, promise: Promise = None
|
||||
) -> None:
|
||||
"""Dispatches an error.
|
||||
|
||||
Args:
|
||||
update (:obj:`str` | :class:`telegram.Update` | None): The update that caused the error
|
||||
update (:obj:`object` | :class:`telegram.Update`): The update that caused the error.
|
||||
error (:obj:`Exception`): The error that was raised.
|
||||
promise (:class:`telegram.utils.Promise`, optional): The promise whose pooled function
|
||||
raised the error.
|
||||
|
||||
+156
-82
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -91,7 +91,7 @@ class BaseFilter(ABC):
|
||||
|
||||
|
||||
If you want to create your own filters create a class inheriting from either
|
||||
:class:`MessageFilter` or :class:`UpdateFilter` and implement a :meth:``filter`` method that
|
||||
:class:`MessageFilter` or :class:`UpdateFilter` and implement a :meth:`filter` method that
|
||||
returns a boolean: :obj:`True` if the message should be
|
||||
handled, :obj:`False` otherwise.
|
||||
Note that the filters work only as class instances, not
|
||||
@@ -148,7 +148,8 @@ class MessageFilter(BaseFilter, ABC):
|
||||
"""Base class for all Message Filters. In contrast to :class:`UpdateFilter`, the object passed
|
||||
to :meth:`filter` is ``update.effective_message``.
|
||||
|
||||
Please see :class:`telegram.ext.BaseFilter` for details on how to create custom filters.
|
||||
Please see :class:`telegram.ext.filters.BaseFilter` for details on how to create custom
|
||||
filters.
|
||||
|
||||
Attributes:
|
||||
name (:obj:`str`): Name for this filter. Defaults to the type of filter.
|
||||
@@ -176,11 +177,12 @@ class MessageFilter(BaseFilter, ABC):
|
||||
|
||||
|
||||
class UpdateFilter(BaseFilter, ABC):
|
||||
"""Base class for all Update Filters. In contrast to :class:`UpdateFilter`, the object
|
||||
"""Base class for all Update Filters. In contrast to :class:`MessageFilter`, the object
|
||||
passed to :meth:`filter` is ``update``, which allows to create filters like
|
||||
:attr:`Filters.update.edited_message`.
|
||||
|
||||
Please see :class:`telegram.ext.BaseFilter` for details on how to create custom filters.
|
||||
Please see :class:`telegram.ext.filters.BaseFilter` for details on how to create custom
|
||||
filters.
|
||||
|
||||
Attributes:
|
||||
name (:obj:`str`): Name for this filter. Defaults to the type of filter.
|
||||
@@ -316,7 +318,7 @@ class MergedFilter(UpdateFilter):
|
||||
|
||||
class XORFilter(UpdateFilter):
|
||||
"""Convenience filter acting as wrapper for :class:`MergedFilter` representing the an XOR gate
|
||||
for two filters
|
||||
for two filters.
|
||||
|
||||
Args:
|
||||
base_filter: Filter 1 of the merged filter.
|
||||
@@ -495,7 +497,7 @@ class Filters:
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(
|
||||
message.entities
|
||||
and any([e.type == MessageEntity.BOT_COMMAND for e in message.entities])
|
||||
and any(e.type == MessageEntity.BOT_COMMAND for e in message.entities)
|
||||
)
|
||||
|
||||
def __call__( # type: ignore[override]
|
||||
@@ -643,7 +645,7 @@ class Filters:
|
||||
send media with wrong types that don't fit to this handler.
|
||||
|
||||
Example:
|
||||
Filters.documents.category('audio/') returns :obj:`True` for all types
|
||||
Filters.document.category('audio/') returns :obj:`True` for all types
|
||||
of audio sent as file, for example 'audio/mpeg' or 'audio/x-wav'.
|
||||
"""
|
||||
|
||||
@@ -677,7 +679,7 @@ class Filters:
|
||||
send media with wrong types that don't fit to this handler.
|
||||
|
||||
Example:
|
||||
``Filters.documents.mime_type('audio/mpeg')`` filters all audio in mp3 format.
|
||||
``Filters.document.mime_type('audio/mpeg')`` filters all audio in mp3 format.
|
||||
"""
|
||||
|
||||
def __init__(self, mimetype: Optional[str]):
|
||||
@@ -794,7 +796,7 @@ class Filters:
|
||||
send media with wrong types that don't fit to this handler.
|
||||
|
||||
Example:
|
||||
``Filters.documents.category('audio/')`` filters all types
|
||||
``Filters.document.category('audio/')`` filters all types
|
||||
of audio sent as file, for example 'audio/mpeg' or 'audio/x-wav'.
|
||||
application: Same as ``Filters.document.category("application")``.
|
||||
audio: Same as ``Filters.document.category("audio")``.
|
||||
@@ -811,23 +813,23 @@ class Filters:
|
||||
send media with wrong types that don't fit to this handler.
|
||||
|
||||
Example:
|
||||
``Filters.documents.mime_type('audio/mpeg')`` filters all audio in mp3 format.
|
||||
apk: Same as ``Filters.document.mime_type("application/vnd.android.package-archive")``-
|
||||
doc: Same as ``Filters.document.mime_type("application/msword")``-
|
||||
``Filters.document.mime_type('audio/mpeg')`` filters all audio in mp3 format.
|
||||
apk: Same as ``Filters.document.mime_type("application/vnd.android.package-archive")``.
|
||||
doc: Same as ``Filters.document.mime_type("application/msword")``.
|
||||
docx: Same as ``Filters.document.mime_type("application/vnd.openxmlformats-\
|
||||
officedocument.wordprocessingml.document")``-
|
||||
exe: Same as ``Filters.document.mime_type("application/x-ms-dos-executable")``-
|
||||
gif: Same as ``Filters.document.mime_type("video/mp4")``-
|
||||
jpg: Same as ``Filters.document.mime_type("image/jpeg")``-
|
||||
mp3: Same as ``Filters.document.mime_type("audio/mpeg")``-
|
||||
pdf: Same as ``Filters.document.mime_type("application/pdf")``-
|
||||
py: Same as ``Filters.document.mime_type("text/x-python")``-
|
||||
svg: Same as ``Filters.document.mime_type("image/svg+xml")``-
|
||||
txt: Same as ``Filters.document.mime_type("text/plain")``-
|
||||
targz: Same as ``Filters.document.mime_type("application/x-compressed-tar")``-
|
||||
wav: Same as ``Filters.document.mime_type("audio/x-wav")``-
|
||||
xml: Same as ``Filters.document.mime_type("application/xml")``-
|
||||
zip: Same as ``Filters.document.mime_type("application/zip")``-
|
||||
officedocument.wordprocessingml.document")``.
|
||||
exe: Same as ``Filters.document.mime_type("application/x-ms-dos-executable")``.
|
||||
gif: Same as ``Filters.document.mime_type("video/mp4")``.
|
||||
jpg: Same as ``Filters.document.mime_type("image/jpeg")``.
|
||||
mp3: Same as ``Filters.document.mime_type("audio/mpeg")``.
|
||||
pdf: Same as ``Filters.document.mime_type("application/pdf")``.
|
||||
py: Same as ``Filters.document.mime_type("text/x-python")``.
|
||||
svg: Same as ``Filters.document.mime_type("image/svg+xml")``.
|
||||
txt: Same as ``Filters.document.mime_type("text/plain")``.
|
||||
targz: Same as ``Filters.document.mime_type("application/x-compressed-tar")``.
|
||||
wav: Same as ``Filters.document.mime_type("audio/x-wav")``.
|
||||
xml: Same as ``Filters.document.mime_type("application/xml")``.
|
||||
zip: Same as ``Filters.document.mime_type("application/zip")``.
|
||||
file_extension: This filter filters documents by their file ending/extension.
|
||||
|
||||
Note:
|
||||
@@ -1003,6 +1005,15 @@ officedocument.wordprocessingml.document")``-
|
||||
:attr: `telegram.Message.supergroup_chat_created` or
|
||||
:attr: `telegram.Message.channel_chat_created`."""
|
||||
|
||||
class _MessageAutoDeleteTimerChanged(MessageFilter):
|
||||
name = 'MessageAutoDeleteTimerChanged'
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.message_auto_delete_timer_changed)
|
||||
|
||||
message_auto_delete_timer_changed = _MessageAutoDeleteTimerChanged()
|
||||
"""Messages that contain :attr:`message_auto_delete_timer_changed`"""
|
||||
|
||||
class _Migrate(MessageFilter):
|
||||
name = 'Filters.status_update.migrate'
|
||||
|
||||
@@ -1040,6 +1051,33 @@ officedocument.wordprocessingml.document")``-
|
||||
proximity_alert_triggered = _ProximityAlertTriggered()
|
||||
"""Messages that contain :attr:`telegram.Message.proximity_alert_triggered`."""
|
||||
|
||||
class _VoiceChatStarted(MessageFilter):
|
||||
name = 'Filters.status_update.voice_chat_started'
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.voice_chat_started)
|
||||
|
||||
voice_chat_started = _VoiceChatStarted()
|
||||
"""Messages that contain :attr:`telegram.Message.voice_chat_started`."""
|
||||
|
||||
class _VoiceChatEnded(MessageFilter):
|
||||
name = 'Filters.status_update.voice_chat_ended'
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.voice_chat_ended)
|
||||
|
||||
voice_chat_ended = _VoiceChatEnded()
|
||||
"""Messages that contain :attr:`telegram.Message.voice_chat_ended`."""
|
||||
|
||||
class _VoiceChatParticipantsInvited(MessageFilter):
|
||||
name = 'Filters.status_update.voice_chat_participants_invited'
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.voice_chat_participants_invited)
|
||||
|
||||
voice_chat_participants_invited = _VoiceChatParticipantsInvited()
|
||||
"""Messages that contain :attr:`telegram.Message.voice_chat_participants_invited`."""
|
||||
|
||||
name = 'Filters.status_update'
|
||||
|
||||
def filter(self, message: Update) -> bool:
|
||||
@@ -1050,10 +1088,14 @@ officedocument.wordprocessingml.document")``-
|
||||
or self.new_chat_photo(message)
|
||||
or self.delete_chat_photo(message)
|
||||
or self.chat_created(message)
|
||||
or self.message_auto_delete_timer_changed(message)
|
||||
or self.migrate(message)
|
||||
or self.pinned_message(message)
|
||||
or self.connected_website(message)
|
||||
or self.proximity_alert_triggered(message)
|
||||
or self.voice_chat_started(message)
|
||||
or self.voice_chat_ended(message)
|
||||
or self.voice_chat_participants_invited(message)
|
||||
)
|
||||
|
||||
status_update = _StatusUpdate()
|
||||
@@ -1075,18 +1117,35 @@ officedocument.wordprocessingml.document")``-
|
||||
left_chat_member: Messages that contain
|
||||
:attr:`telegram.Message.left_chat_member`.
|
||||
migrate: Messages that contain
|
||||
:attr:`telegram.Message.migrate_from_chat_id` or
|
||||
:attr: `telegram.Message.migrate_from_chat_id`.
|
||||
:attr:`telegram.Message.migrate_to_chat_id` or
|
||||
:attr:`telegram.Message.migrate_from_chat_id`.
|
||||
new_chat_members: Messages that contain
|
||||
:attr:`telegram.Message.new_chat_members`.
|
||||
new_chat_photo: Messages that contain
|
||||
:attr:`telegram.Message.new_chat_photo`.
|
||||
new_chat_title: Messages that contain
|
||||
:attr:`telegram.Message.new_chat_title`.
|
||||
message_auto_delete_timer_changed: Messages that contain
|
||||
:attr:`message_auto_delete_timer_changed`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
pinned_message: Messages that contain
|
||||
:attr:`telegram.Message.pinned_message`.
|
||||
proximity_alert_triggered: Messages that contain
|
||||
:attr:`telegram.Message.proximity_alert_triggered`.
|
||||
voice_chat_started: Messages that contain
|
||||
:attr:`telegram.Message.voice_chat_started`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
voice_chat_ended: Messages that contain
|
||||
:attr:`telegram.Message.voice_chat_ended`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
voice_chat_participants_invited: Messages that contain
|
||||
:attr:`telegram.Message.voice_chat_participants_invited`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
"""
|
||||
|
||||
class _Forwarded(MessageFilter):
|
||||
@@ -1409,24 +1468,25 @@ officedocument.wordprocessingml.document")``-
|
||||
that it is not causing race conditions, as this will complete replace the current set
|
||||
of allowed users.
|
||||
|
||||
Attributes:
|
||||
user_ids(set(:obj:`int`), optional): Which user ID(s) to allow through.
|
||||
usernames(set(:obj:`str`), optional): Which username(s) (without leading '@') to allow
|
||||
through.
|
||||
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user
|
||||
is specified in :attr:`user_ids` and :attr:`usernames`.
|
||||
|
||||
Args:
|
||||
user_id(:class:`telegram.utils.types.SLT[int]`, optional):
|
||||
Which user ID(s) to allow through.
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which username(s) to allow through. Leading '@'s in usernames will be discarded.
|
||||
Which username(s) to allow through. Leading ``'@'`` s in usernames will be
|
||||
discarded.
|
||||
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user
|
||||
is specified in :attr:`user_ids` and :attr:`usernames`. Defaults to :obj:`False`
|
||||
|
||||
Raises:
|
||||
RuntimeError: If user_id and username are both present.
|
||||
|
||||
Attributes:
|
||||
user_ids(set(:obj:`int`), optional): Which user ID(s) to allow through.
|
||||
usernames(set(:obj:`str`), optional): Which username(s) (without leading ``'@'``) to
|
||||
allow through.
|
||||
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user
|
||||
is specified in :attr:`user_ids` and :attr:`usernames`.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -1456,7 +1516,7 @@ officedocument.wordprocessingml.document")``-
|
||||
Args:
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which username(s) to allow through.
|
||||
Leading '@'s in usernames will be discarded.
|
||||
Leading ``'@'`` s in usernames will be discarded.
|
||||
"""
|
||||
return super().add_usernames(username)
|
||||
|
||||
@@ -1477,7 +1537,7 @@ officedocument.wordprocessingml.document")``-
|
||||
Args:
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which username(s) to disallow through.
|
||||
Leading '@'s in usernames will be discarded.
|
||||
Leading ``'@'`` s in usernames will be discarded.
|
||||
"""
|
||||
return super().remove_usernames(username)
|
||||
|
||||
@@ -1507,23 +1567,25 @@ officedocument.wordprocessingml.document")``-
|
||||
that it is not causing race conditions, as this will complete replace the current set
|
||||
of allowed bots.
|
||||
|
||||
Attributes:
|
||||
bot_ids(set(:obj:`int`), optional): Which bot ID(s) to allow through.
|
||||
usernames(set(:obj:`str`), optional): Which username(s) (without leading '@') to allow
|
||||
through.
|
||||
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no bot
|
||||
is specified in :attr:`bot_ids` and :attr:`usernames`.
|
||||
|
||||
Args:
|
||||
bot_id(:class:`telegram.utils.types.SLT[int]`, optional):
|
||||
Which bot ID(s) to allow through.
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which username(s) to allow through. Leading '@'s in usernames will be discarded.
|
||||
Which username(s) to allow through. Leading ``'@'`` s in usernames will be
|
||||
discarded.
|
||||
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user
|
||||
is specified in :attr:`bot_ids` and :attr:`usernames`. Defaults to :obj:`False`
|
||||
|
||||
Raises:
|
||||
RuntimeError: If bot_id and username are both present.
|
||||
|
||||
Attributes:
|
||||
bot_ids(set(:obj:`int`), optional): Which bot ID(s) to allow through.
|
||||
usernames(set(:obj:`str`), optional): Which username(s) (without leading ``'@'``) to
|
||||
allow through.
|
||||
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no bot
|
||||
is specified in :attr:`bot_ids` and :attr:`usernames`.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -1553,7 +1615,7 @@ officedocument.wordprocessingml.document")``-
|
||||
Args:
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which username(s) to allow through.
|
||||
Leading '@'s in usernames will be discarded.
|
||||
Leading ``'@'`` s in usernames will be discarded.
|
||||
"""
|
||||
return super().add_usernames(username)
|
||||
|
||||
@@ -1575,7 +1637,7 @@ officedocument.wordprocessingml.document")``-
|
||||
Args:
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which username(s) to disallow through.
|
||||
Leading '@'s in usernames will be discarded.
|
||||
Leading ``'@'`` s in usernames will be discarded.
|
||||
"""
|
||||
return super().remove_usernames(username)
|
||||
|
||||
@@ -1604,25 +1666,25 @@ officedocument.wordprocessingml.document")``-
|
||||
that it is not causing race conditions, as this will complete replace the current set
|
||||
of allowed chats.
|
||||
|
||||
Attributes:
|
||||
chat_ids(set(:obj:`int`), optional): Which chat ID(s) to allow through.
|
||||
usernames(set(:obj:`str`), optional): Which username(s) (without leading '@') to allow
|
||||
through.
|
||||
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat
|
||||
is specified in :attr:`chat_ids` and :attr:`usernames`.
|
||||
|
||||
Args:
|
||||
chat_id(:class:`telegram.utils.types.SLT[int]`, optional):
|
||||
Which chat ID(s) to allow through.
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which username(s) to allow through.
|
||||
Leading `'@'` s in usernames will be discarded.
|
||||
Leading ``'@'`` s in usernames will be discarded.
|
||||
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat
|
||||
is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False`
|
||||
|
||||
Raises:
|
||||
RuntimeError: If chat_id and username are both present.
|
||||
|
||||
Attributes:
|
||||
chat_ids(set(:obj:`int`), optional): Which chat ID(s) to allow through.
|
||||
usernames(set(:obj:`str`), optional): Which username(s) (without leading ``'@'``) to
|
||||
allow through.
|
||||
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat
|
||||
is specified in :attr:`chat_ids` and :attr:`usernames`.
|
||||
|
||||
"""
|
||||
|
||||
def get_chat_or_user(self, message: Message) -> Optional[Chat]:
|
||||
@@ -1635,7 +1697,7 @@ officedocument.wordprocessingml.document")``-
|
||||
Args:
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which username(s) to allow through.
|
||||
Leading `'@'` s in usernames will be discarded.
|
||||
Leading ``'@'`` s in usernames will be discarded.
|
||||
"""
|
||||
return super().add_usernames(username)
|
||||
|
||||
@@ -1656,7 +1718,7 @@ officedocument.wordprocessingml.document")``-
|
||||
Args:
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which username(s) to disallow through.
|
||||
Leading '@'s in usernames will be discarded.
|
||||
Leading ``'@'`` s in usernames will be discarded.
|
||||
"""
|
||||
return super().remove_usernames(username)
|
||||
|
||||
@@ -1676,16 +1738,22 @@ officedocument.wordprocessingml.document")``-
|
||||
username.
|
||||
|
||||
Examples:
|
||||
* To filter for messages forwarded from a channel with ID ``-1234``, use
|
||||
``MessageHandler(Filters.sender_chat(-1234), callback_method)``.
|
||||
* To filter for messages forwarded to a discussion group from a channel with ID
|
||||
``-1234``, use ``MessageHandler(Filters.sender_chat(-1234), callback_method)``.
|
||||
* To filter for messages of anonymous admins in a super group with username
|
||||
``@anonymous``, use
|
||||
``MessageHandler(Filters.sender_chat(username='anonymous'), callback_method)``.
|
||||
* To filter for messages forwarded from *any* channel, use
|
||||
* To filter for messages forwarded to a discussion group from *any* channel, use
|
||||
``MessageHandler(Filters.sender_chat.channel, callback_method)``.
|
||||
* To filter for messages of anonymous admins in *any* super group, use
|
||||
``MessageHandler(Filters.sender_chat.super_group, callback_method)``.
|
||||
|
||||
Note:
|
||||
Remember, ``sender_chat`` is also set for messages in a channel as the channel itself,
|
||||
so when your bot is an admin in a channel and the linked discussion group, you would
|
||||
receive the message twice (once from inside the channel, once inside the discussion
|
||||
group).
|
||||
|
||||
Warning:
|
||||
:attr:`chat_ids` will return a *copy* of the saved chat ids as :class:`frozenset`. This
|
||||
is to ensure thread safety. To add/remove a chat, you should use :meth:`add_usernames`,
|
||||
@@ -1694,10 +1762,23 @@ officedocument.wordprocessingml.document")``-
|
||||
that it is not causing race conditions, as this will complete replace the current set
|
||||
of allowed chats.
|
||||
|
||||
Args:
|
||||
chat_id(:class:`telegram.utils.types.SLT[int]`, optional):
|
||||
Which sender chat chat ID(s) to allow through.
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which sender chat username(s) to allow through.
|
||||
Leading ``'@'`` s in usernames will be discarded.
|
||||
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no sender
|
||||
chat is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to
|
||||
:obj:`False`
|
||||
|
||||
Raises:
|
||||
RuntimeError: If both chat_id and username are present.
|
||||
|
||||
Attributes:
|
||||
chat_ids(set(:obj:`int`), optional): Which sender chat chat ID(s) to allow through.
|
||||
usernames(set(:obj:`str`), optional): Which sender chat username(s) (without leading
|
||||
'@') to allow through.
|
||||
``'@'``) to allow through.
|
||||
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no sender
|
||||
chat is specified in :attr:`chat_ids` and :attr:`usernames`.
|
||||
super_group: Messages whose sender chat is a super group.
|
||||
@@ -1709,19 +1790,6 @@ officedocument.wordprocessingml.document")``-
|
||||
Examples:
|
||||
``Filters.sender_chat.channel``
|
||||
|
||||
Args:
|
||||
chat_id(:class:`telegram.utils.types.SLT[int]`, optional):
|
||||
Which sender chat chat ID(s) to allow through.
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which sender chat sername(s) to allow through.
|
||||
Leading `'@'` s in usernames will be discarded.
|
||||
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no sender
|
||||
chat is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to
|
||||
:obj:`False`
|
||||
|
||||
Raises:
|
||||
RuntimeError: If chat_id and username are both present.
|
||||
|
||||
"""
|
||||
|
||||
def get_chat_or_user(self, message: Message) -> Optional[Chat]:
|
||||
@@ -1734,7 +1802,7 @@ officedocument.wordprocessingml.document")``-
|
||||
Args:
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which sender chat username(s) to allow through.
|
||||
Leading `'@'` s in usernames will be discarded.
|
||||
Leading ``'@'`` s in usernames will be discarded.
|
||||
"""
|
||||
return super().add_usernames(username)
|
||||
|
||||
@@ -1755,7 +1823,7 @@ officedocument.wordprocessingml.document")``-
|
||||
Args:
|
||||
username(:class:`telegram.utils.types.SLT[str]`, optional):
|
||||
Which sender chat username(s) to disallow through.
|
||||
Leading '@'s in usernames will be discarded.
|
||||
Leading ``'@'`` s in usernames will be discarded.
|
||||
"""
|
||||
return super().remove_usernames(username)
|
||||
|
||||
@@ -1826,6 +1894,7 @@ officedocument.wordprocessingml.document")``-
|
||||
basketball = _DiceEmoji('🏀', 'basketball')
|
||||
football = _DiceEmoji('⚽')
|
||||
slot_machine = _DiceEmoji('🎰')
|
||||
bowling = _DiceEmoji('🎳', 'bowling')
|
||||
|
||||
dice = _Dice()
|
||||
"""Dice Messages. If an integer or a list of integers is passed, it filters messages to only
|
||||
@@ -1839,14 +1908,14 @@ officedocument.wordprocessingml.document")``-
|
||||
To allow only dice with value 5 `or` 6, use
|
||||
``MessageHandler(Filters.dice([5, 6]), callback_method)``.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.utils.types.SLT[int]`, optional):
|
||||
Which values to allow. If not specified, will allow any dice message.
|
||||
|
||||
Note:
|
||||
Dice messages don't have text. If you want to filter either text or dice messages, use
|
||||
``Filters.text | Filters.dice``.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.utils.types.SLT[int]`, optional):
|
||||
Which values to allow. If not specified, will allow any dice message.
|
||||
|
||||
Attributes:
|
||||
dice: Dice messages with the emoji 🎲. Passing a list of integers is supported just as for
|
||||
:attr:`Filters.dice`.
|
||||
@@ -1858,6 +1927,11 @@ officedocument.wordprocessingml.document")``-
|
||||
as for :attr:`Filters.dice`.
|
||||
slot_machine: Dice messages with the emoji 🎰. Passing a list of integers is supported just
|
||||
as for :attr:`Filters.dice`.
|
||||
bowling: Dice messages with the emoji 🎳. Passing a list of integers is supported just
|
||||
as for :attr:`Filters.dice`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
"""
|
||||
|
||||
class language(MessageFilter):
|
||||
@@ -1891,7 +1965,7 @@ officedocument.wordprocessingml.document")``-
|
||||
"""""" # remove method from docs
|
||||
return bool(
|
||||
message.from_user.language_code
|
||||
and any([message.from_user.language_code.startswith(x) for x in self.lang])
|
||||
and any(message.from_user.language_code.startswith(x) for x in self.lang)
|
||||
)
|
||||
|
||||
class _UpdateType(UpdateFilter):
|
||||
|
||||
+29
-25
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -19,34 +19,22 @@
|
||||
"""This module contains the base class for handlers as used by the Dispatcher."""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, TypeVar, Union
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, TypeVar, Union, Generic
|
||||
|
||||
from telegram import Update
|
||||
from telegram.utils.promise import Promise
|
||||
from telegram.utils.types import HandlerArg
|
||||
from telegram.ext.utils.promise import Promise
|
||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
RT = TypeVar('RT')
|
||||
UT = TypeVar('UT')
|
||||
|
||||
|
||||
class Handler(ABC):
|
||||
class Handler(Generic[UT], ABC):
|
||||
"""The base class for all update handlers. Create custom handlers by inheriting from it.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
@@ -88,18 +76,30 @@ class Handler(ABC):
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
callback: Callable[[UT, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
|
||||
):
|
||||
self.callback: Callable[[HandlerArg, 'CallbackContext'], RT] = callback
|
||||
self.callback = callback
|
||||
self.pass_update_queue = pass_update_queue
|
||||
self.pass_job_queue = pass_job_queue
|
||||
self.pass_user_data = pass_user_data
|
||||
@@ -107,11 +107,15 @@ class Handler(ABC):
|
||||
self.run_async = run_async
|
||||
|
||||
@abstractmethod
|
||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, object]]:
|
||||
def check_update(self, update: object) -> Optional[Union[bool, object]]:
|
||||
"""
|
||||
This method is called to determine if an update should be handled by
|
||||
this handler instance. It should always be overridden.
|
||||
|
||||
Note:
|
||||
Custom updates types can be handled by the dispatcher. Therefore, an implementation of
|
||||
this method should always check the type of :attr:`update`.
|
||||
|
||||
Args:
|
||||
update (:obj:`str` | :class:`telegram.Update`): The update to be tested.
|
||||
|
||||
@@ -124,7 +128,7 @@ class Handler(ABC):
|
||||
|
||||
def handle_update(
|
||||
self,
|
||||
update: HandlerArg,
|
||||
update: UT,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: object,
|
||||
context: 'CallbackContext' = None,
|
||||
@@ -165,7 +169,7 @@ class Handler(ABC):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
update: UT,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Any,
|
||||
) -> None:
|
||||
@@ -182,9 +186,9 @@ class Handler(ABC):
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
update: UT = None,
|
||||
check_result: Any = None, # pylint: disable=W0613
|
||||
) -> Dict[str, Any]:
|
||||
) -> Dict[str, object]:
|
||||
"""
|
||||
Prepares the optional arguments. If the handler has additional optional args,
|
||||
it should subclass this method, but remember to call this super method.
|
||||
@@ -198,7 +202,7 @@ class Handler(ABC):
|
||||
check_result: The result from check_update
|
||||
|
||||
"""
|
||||
optional_args: Dict[str, Any] = dict()
|
||||
optional_args: Dict[str, object] = dict()
|
||||
|
||||
if self.pass_update_queue:
|
||||
optional_args['update_queue'] = dispatcher.update_queue
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -20,7 +20,6 @@
|
||||
import re
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Callable,
|
||||
Dict,
|
||||
Match,
|
||||
@@ -32,7 +31,6 @@ from typing import (
|
||||
)
|
||||
|
||||
from telegram import Update
|
||||
from telegram.utils.types import HandlerArg
|
||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||
|
||||
from .handler import Handler
|
||||
@@ -43,29 +41,11 @@ if TYPE_CHECKING:
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class InlineQueryHandler(Handler):
|
||||
class InlineQueryHandler(Handler[Update]):
|
||||
"""
|
||||
Handler class to handle Telegram inline queries. Optionally based on a regex. Read the
|
||||
documentation of the ``re`` module for more information.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pattern (:obj:`str` | :obj:`Pattern`): Optional. Regex pattern to test
|
||||
:attr:`telegram.InlineQuery.query` against.
|
||||
pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the
|
||||
callback function.
|
||||
pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
@@ -118,11 +98,29 @@ class InlineQueryHandler(Handler):
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pattern (:obj:`str` | :obj:`Pattern`): Optional. Regex pattern to test
|
||||
:attr:`telegram.InlineQuery.query` against.
|
||||
pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the
|
||||
callback function.
|
||||
pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
callback: Callable[[Update, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pattern: Union[str, Pattern] = None,
|
||||
@@ -148,12 +146,12 @@ class InlineQueryHandler(Handler):
|
||||
self.pass_groups = pass_groups
|
||||
self.pass_groupdict = pass_groupdict
|
||||
|
||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, Match]]:
|
||||
def check_update(self, update: object) -> Optional[Union[bool, Match]]:
|
||||
"""
|
||||
Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
@@ -173,9 +171,9 @@ class InlineQueryHandler(Handler):
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
update: Update = None,
|
||||
check_result: Optional[Union[bool, Match]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
) -> Dict[str, object]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pattern:
|
||||
check_result = cast(Match, check_result)
|
||||
@@ -188,7 +186,7 @@ class InlineQueryHandler(Handler):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
update: Update,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Match]],
|
||||
) -> None:
|
||||
|
||||
+16
-15
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -16,18 +16,18 @@
|
||||
#
|
||||
# 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=E0401
|
||||
"""This module contains the classes JobQueue and Job."""
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any, Callable, List, Optional, Tuple, Union, cast, overload
|
||||
from typing import TYPE_CHECKING, Callable, List, Optional, Tuple, Union, cast, overload
|
||||
|
||||
import pytz
|
||||
from apscheduler.events import EVENT_JOB_ERROR, EVENT_JOB_EXECUTED, JobEvent
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.combining import OrTrigger
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from apscheduler.job import Job as APSJob
|
||||
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.utils.types import JSONDict
|
||||
@@ -35,6 +35,7 @@ from telegram.utils.types import JSONDict
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
from telegram.ext import Dispatcher
|
||||
import apscheduler.job # noqa: F401
|
||||
|
||||
|
||||
class Days:
|
||||
@@ -409,7 +410,7 @@ class JobQueue:
|
||||
time (:obj:`datetime.time`): Time of day at which the job should run. If the timezone
|
||||
(``time.tzinfo``) is :obj:`None`, the default timezone of the bot will be used.
|
||||
days (Tuple[:obj:`int`], optional): Defines on which days of the week the job should
|
||||
run. Defaults to ``EVERY_DAY``
|
||||
run (where ``0-6`` correspond to monday - sunday). Defaults to ``EVERY_DAY``
|
||||
context (:obj:`object`, optional): Additional data needed for the callback function.
|
||||
Can be accessed through ``job.context`` in the callback. Defaults to :obj:`None`.
|
||||
name (:obj:`str`, optional): The name of the new job. Defaults to
|
||||
@@ -522,13 +523,6 @@ class Job:
|
||||
* If :attr:`job` isn't passed on initialization, it must be set manually afterwards for
|
||||
this :class:`telegram.ext.Job` to be useful.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function that should be executed by the new job.
|
||||
context (:obj:`object`): Optional. Additional data needed for the callback function.
|
||||
name (:obj:`str`): Optional. The name of the new job.
|
||||
job_queue (:class:`telegram.ext.JobQueue`): Optional. The ``JobQueue`` this job belongs to.
|
||||
job (:class:`apscheduler.job.Job`): Optional. The APS Job this job is a wrapper for.
|
||||
|
||||
Args:
|
||||
callback (:obj:`callable`): The callback function that should be executed by the new job.
|
||||
Callback signature for context based API:
|
||||
@@ -543,6 +537,13 @@ class Job:
|
||||
job_queue (:class:`telegram.ext.JobQueue`, optional): The ``JobQueue`` this job belongs to.
|
||||
Only optional for backward compatibility with ``JobQueue.put()``.
|
||||
job (:class:`apscheduler.job.Job`, optional): The APS Job this job is a wrapper for.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function that should be executed by the new job.
|
||||
context (:obj:`object`): Optional. Additional data needed for the callback function.
|
||||
name (:obj:`str`): Optional. The name of the new job.
|
||||
job_queue (:class:`telegram.ext.JobQueue`): Optional. The ``JobQueue`` this job belongs to.
|
||||
job (:class:`apscheduler.job.Job`): Optional. The APS Job this job is a wrapper for.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -551,7 +552,7 @@ class Job:
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_queue: JobQueue = None,
|
||||
job: 'Job' = None,
|
||||
job: APSJob = None,
|
||||
):
|
||||
|
||||
self.callback = callback
|
||||
@@ -562,7 +563,7 @@ class Job:
|
||||
self._removed = False
|
||||
self._enabled = False
|
||||
|
||||
self.job = cast('Job', job)
|
||||
self.job = cast(APSJob, job)
|
||||
|
||||
def run(self, dispatcher: 'Dispatcher') -> None:
|
||||
"""Executes the callback function independently of the jobs schedule."""
|
||||
@@ -618,7 +619,7 @@ class Job:
|
||||
return self.job.next_run_time
|
||||
|
||||
@classmethod
|
||||
def from_aps_job(cls, job: 'Job', job_queue: JobQueue) -> 'Job':
|
||||
def from_aps_job(cls, job: APSJob, job_queue: JobQueue) -> 'Job':
|
||||
# context based callbacks
|
||||
if len(job.args) == 1:
|
||||
context = job.args[0].job.context
|
||||
@@ -626,7 +627,7 @@ class Job:
|
||||
context = job.args[1].context
|
||||
return cls(job.func, context=context, name=job.name, job_queue=job_queue, job=job)
|
||||
|
||||
def __getattr__(self, item: str) -> Any:
|
||||
def __getattr__(self, item: str) -> object:
|
||||
return getattr(self.job, item)
|
||||
|
||||
def __lt__(self, other: object) -> bool:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -19,12 +19,11 @@
|
||||
# TODO: Remove allow_edited
|
||||
"""This module contains the MessageHandler class."""
|
||||
import warnings
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, TypeVar, Union
|
||||
from typing import TYPE_CHECKING, Callable, Dict, Optional, TypeVar, Union
|
||||
|
||||
from telegram import Update
|
||||
from telegram.ext import BaseFilter, Filters
|
||||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
||||
from telegram.utils.types import HandlerArg
|
||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||
|
||||
from .handler import Handler
|
||||
@@ -35,29 +34,9 @@ if TYPE_CHECKING:
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class MessageHandler(Handler):
|
||||
class MessageHandler(Handler[Update]):
|
||||
"""Handler class to handle telegram messages. They might contain text, media or status updates.
|
||||
|
||||
Attributes:
|
||||
filters (:obj:`Filter`): Only allow updates with these Filters. See
|
||||
:mod:`telegram.ext.filters` for a full list of all available filters.
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
message_updates (:obj:`bool`): Should "normal" message updates be handled?
|
||||
Default is :obj:`None`.
|
||||
channel_post_updates (:obj:`bool`): Should channel posts updates be handled?
|
||||
Default is :obj:`None`.
|
||||
edited_updates (:obj:`bool`): Should "edited" message updates be handled?
|
||||
Default is :obj:`None`.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
@@ -119,12 +98,32 @@ class MessageHandler(Handler):
|
||||
Raises:
|
||||
ValueError
|
||||
|
||||
Attributes:
|
||||
filters (:obj:`Filter`): Only allow updates with these Filters. See
|
||||
:mod:`telegram.ext.filters` for a full list of all available filters.
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
message_updates (:obj:`bool`): Should "normal" message updates be handled?
|
||||
Default is :obj:`None`.
|
||||
channel_post_updates (:obj:`bool`): Should channel posts updates be handled?
|
||||
Default is :obj:`None`.
|
||||
edited_updates (:obj:`bool`): Should "edited" message updates be handled?
|
||||
Default is :obj:`None`.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
filters: BaseFilter,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
callback: Callable[[Update, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
@@ -180,11 +179,11 @@ class MessageHandler(Handler):
|
||||
Filters.update.edited_message | Filters.update.edited_channel_post
|
||||
)
|
||||
|
||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, Dict[str, Any]]]:
|
||||
def check_update(self, update: object) -> Optional[Union[bool, Dict[str, object]]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
@@ -197,9 +196,9 @@ class MessageHandler(Handler):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
update: Update,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Dict[str, Any]]],
|
||||
check_result: Optional[Union[bool, Dict[str, object]]],
|
||||
) -> None:
|
||||
if isinstance(check_result, dict):
|
||||
context.update(check_result)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Tymofii A. Khodniev (thodnev) <thodnev@mail.ru>
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -24,9 +24,11 @@ import functools
|
||||
import queue as q
|
||||
import threading
|
||||
import time
|
||||
from typing import TYPE_CHECKING, Any, Callable, List, NoReturn
|
||||
import warnings
|
||||
from typing import TYPE_CHECKING, Callable, List, NoReturn
|
||||
|
||||
from telegram.utils.promise import Promise
|
||||
from telegram.ext.utils.promise import Promise
|
||||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
@@ -44,13 +46,9 @@ class DelayQueue(threading.Thread):
|
||||
Processes callbacks from queue with specified throughput limits. Creates a separate thread to
|
||||
process callbacks with delays.
|
||||
|
||||
Attributes:
|
||||
burst_limit (:obj:`int`): Number of maximum callbacks to process per time-window.
|
||||
time_limit (:obj:`int`): Defines width of time-window used when each processing limit is
|
||||
calculated.
|
||||
exc_route (:obj:`callable`): A callable, accepting 1 positional argument; used to route
|
||||
exceptions from processor thread to main thread;
|
||||
name (:obj:`str`): Thread's name.
|
||||
.. deprecated:: 13.3
|
||||
:class:`telegram.ext.DelayQueue` in its current form is deprecated and will be reinvented
|
||||
in a future release. See `this thread <https://git.io/JtDbF>`_ for a list of known bugs.
|
||||
|
||||
Args:
|
||||
queue (:obj:`Queue`, optional): Used to pass callbacks to thread. Creates ``Queue``
|
||||
@@ -69,6 +67,14 @@ class DelayQueue(threading.Thread):
|
||||
name (:obj:`str`, optional): Thread's name. Defaults to ``'DelayQueue-N'``, where N is
|
||||
sequential number of object created.
|
||||
|
||||
Attributes:
|
||||
burst_limit (:obj:`int`): Number of maximum callbacks to process per time-window.
|
||||
time_limit (:obj:`int`): Defines width of time-window used when each processing limit is
|
||||
calculated.
|
||||
exc_route (:obj:`callable`): A callable, accepting 1 positional argument; used to route
|
||||
exceptions from processor thread to main thread;
|
||||
name (:obj:`str`): Thread's name.
|
||||
|
||||
"""
|
||||
|
||||
_instcnt = 0 # instance counter
|
||||
@@ -82,6 +88,12 @@ class DelayQueue(threading.Thread):
|
||||
autostart: bool = True,
|
||||
name: str = None,
|
||||
):
|
||||
warnings.warn(
|
||||
'DelayQueue in its current form is deprecated and will be reinvented in a future '
|
||||
'release. See https://git.io/JtDbF for a list of known bugs.',
|
||||
category=TelegramDeprecationWarning,
|
||||
)
|
||||
|
||||
self._queue = queue if queue is not None else q.Queue()
|
||||
self.burst_limit = burst_limit
|
||||
self.time_limit = time_limit_ms / 1000
|
||||
@@ -153,7 +165,7 @@ class DelayQueue(threading.Thread):
|
||||
|
||||
raise exc
|
||||
|
||||
def __call__(self, func: Callable, *args: Any, **kwargs: Any) -> None:
|
||||
def __call__(self, func: Callable, *args: object, **kwargs: object) -> None:
|
||||
"""Used to process callbacks in throughput-limiting thread through queue.
|
||||
|
||||
Args:
|
||||
@@ -182,6 +194,10 @@ class MessageQueue:
|
||||
Callables are processed through *group* ``DelayQueue``, then through *all* ``DelayQueue`` for
|
||||
group-type messages. For non-group messages, only the *all* ``DelayQueue`` is used.
|
||||
|
||||
.. deprecated:: 13.3
|
||||
:class:`telegram.ext.MessageQueue` in its current form is deprecated and will be reinvented
|
||||
in a future release. See `this thread <https://git.io/JtDbF>`_ for a list of known bugs.
|
||||
|
||||
Args:
|
||||
all_burst_limit (:obj:`int`, optional): Number of maximum *all-type* callbacks to process
|
||||
per time-window defined by :attr:`all_time_limit_ms`. Defaults to 30.
|
||||
@@ -210,6 +226,12 @@ class MessageQueue:
|
||||
exc_route: Callable[[Exception], None] = None,
|
||||
autostart: bool = True,
|
||||
):
|
||||
warnings.warn(
|
||||
'MessageQueue in its current form is deprecated and will be reinvented in a future '
|
||||
'release. See https://git.io/JtDbF for a list of known bugs.',
|
||||
category=TelegramDeprecationWarning,
|
||||
)
|
||||
|
||||
# create according delay queues, use composition
|
||||
self._all_delayq = DelayQueue(
|
||||
burst_limit=all_burst_limit,
|
||||
@@ -300,7 +322,7 @@ def queuedmessage(method: Callable) -> Callable:
|
||||
"""
|
||||
|
||||
@functools.wraps(method)
|
||||
def wrapped(self: 'Bot', *args: Any, **kwargs: Any) -> Any:
|
||||
def wrapped(self: 'Bot', *args: object, **kwargs: object) -> object:
|
||||
# pylint: disable=W0212
|
||||
queued = kwargs.pop(
|
||||
'queued', self._is_messages_queued_default # type: ignore[attr-defined]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -38,23 +38,6 @@ class PicklePersistence(BasePersistence):
|
||||
:meth:`telegram.ext.BasePersistence.replace_bot` and
|
||||
:meth:`telegram.ext.BasePersistence.insert_bot`.
|
||||
|
||||
Attributes:
|
||||
filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file`
|
||||
is :obj:`False` this will be used as a prefix.
|
||||
store_user_data (:obj:`bool`): Optional. Whether user_data should be saved by this
|
||||
persistence class.
|
||||
store_chat_data (:obj:`bool`): Optional. Whether user_data should be saved by this
|
||||
persistence class.
|
||||
store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this
|
||||
persistence class.
|
||||
single_file (:obj:`bool`): Optional. When :obj:`False` will store 3 separate files of
|
||||
`filename_user_data`, `filename_chat_data` and `filename_conversations`. Default is
|
||||
:obj:`True`.
|
||||
on_flush (:obj:`bool`, optional): When :obj:`True` will only save to file when
|
||||
:meth:`flush` is called and keep data in memory until that happens. When
|
||||
:obj:`False` will store data on any transaction *and* on call to :meth:`flush`.
|
||||
Default is :obj:`False`.
|
||||
|
||||
Args:
|
||||
filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file`
|
||||
is :obj:`False` this will be used as a prefix.
|
||||
@@ -71,6 +54,23 @@ class PicklePersistence(BasePersistence):
|
||||
:meth:`flush` is called and keep data in memory until that happens. When
|
||||
:obj:`False` will store data on any transaction *and* on call to :meth:`flush`.
|
||||
Default is :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file`
|
||||
is :obj:`False` this will be used as a prefix.
|
||||
store_user_data (:obj:`bool`): Optional. Whether user_data should be saved by this
|
||||
persistence class.
|
||||
store_chat_data (:obj:`bool`): Optional. Whether user_data should be saved by this
|
||||
persistence class.
|
||||
store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this
|
||||
persistence class.
|
||||
single_file (:obj:`bool`): Optional. When :obj:`False` will store 3 separate files of
|
||||
`filename_user_data`, `filename_chat_data` and `filename_conversations`. Default is
|
||||
:obj:`True`.
|
||||
on_flush (:obj:`bool`, optional): When :obj:`True` will only save to file when
|
||||
:meth:`flush` is called and keep data in memory until that happens. When
|
||||
:obj:`False` will store data on any transaction *and* on call to :meth:`flush`.
|
||||
Default is :obj:`False`.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -93,7 +93,7 @@ class PicklePersistence(BasePersistence):
|
||||
self.user_data: Optional[DefaultDict[int, Dict]] = None
|
||||
self.chat_data: Optional[DefaultDict[int, Dict]] = None
|
||||
self.bot_data: Optional[Dict] = None
|
||||
self.conversations: Optional[Dict[str, Dict[Tuple, Any]]] = None
|
||||
self.conversations: Optional[Dict[str, Dict[Tuple, object]]] = None
|
||||
|
||||
def load_singlefile(self) -> None:
|
||||
try:
|
||||
@@ -105,7 +105,7 @@ class PicklePersistence(BasePersistence):
|
||||
# For backwards compatibility with files not containing bot data
|
||||
self.bot_data = data.get('bot_data', {})
|
||||
self.conversations = data['conversations']
|
||||
except IOError:
|
||||
except OSError:
|
||||
self.conversations = dict()
|
||||
self.user_data = defaultdict(dict)
|
||||
self.chat_data = defaultdict(dict)
|
||||
@@ -120,7 +120,7 @@ class PicklePersistence(BasePersistence):
|
||||
try:
|
||||
with open(filename, "rb") as file:
|
||||
return pickle.load(file)
|
||||
except IOError:
|
||||
except OSError:
|
||||
return None
|
||||
except pickle.UnpicklingError as exc:
|
||||
raise TypeError(f"File {filename} does not contain valid pickle data") from exc
|
||||
@@ -138,11 +138,11 @@ class PicklePersistence(BasePersistence):
|
||||
pickle.dump(data, file)
|
||||
|
||||
@staticmethod
|
||||
def dump_file(filename: str, data: Any) -> None:
|
||||
def dump_file(filename: str, data: object) -> None:
|
||||
with open(filename, "wb") as file:
|
||||
pickle.dump(data, file)
|
||||
|
||||
def get_user_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||
def get_user_data(self) -> DefaultDict[int, Dict[object, object]]:
|
||||
"""Returns the user_data from the pickle file if it exists or an empty :obj:`defaultdict`.
|
||||
|
||||
Returns:
|
||||
@@ -162,7 +162,7 @@ class PicklePersistence(BasePersistence):
|
||||
self.load_singlefile()
|
||||
return deepcopy(self.user_data) # type: ignore[arg-type]
|
||||
|
||||
def get_chat_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||
def get_chat_data(self) -> DefaultDict[int, Dict[object, object]]:
|
||||
"""Returns the chat_data from the pickle file if it exists or an empty :obj:`defaultdict`.
|
||||
|
||||
Returns:
|
||||
@@ -182,7 +182,7 @@ class PicklePersistence(BasePersistence):
|
||||
self.load_singlefile()
|
||||
return deepcopy(self.chat_data) # type: ignore[arg-type]
|
||||
|
||||
def get_bot_data(self) -> Dict[Any, Any]:
|
||||
def get_bot_data(self) -> Dict[object, object]:
|
||||
"""Returns the bot_data from the pickle file if it exists or an empty :obj:`dict`.
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2019
|
||||
# Copyright (C) 2019-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -18,27 +18,15 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the PollAnswerHandler class."""
|
||||
|
||||
|
||||
from telegram import Update
|
||||
from telegram.utils.types import HandlerArg
|
||||
|
||||
from .handler import Handler
|
||||
|
||||
|
||||
class PollAnswerHandler(Handler):
|
||||
class PollAnswerHandler(Handler[Update]):
|
||||
"""Handler class to handle Telegram updates that contain a poll answer.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
@@ -80,13 +68,25 @@ class PollAnswerHandler(Handler):
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def check_update(self, update: HandlerArg) -> bool:
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
+17
-17
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2019
|
||||
# Copyright (C) 2019-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -18,27 +18,15 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the PollHandler classes."""
|
||||
|
||||
|
||||
from telegram import Update
|
||||
from telegram.utils.types import HandlerArg
|
||||
|
||||
from .handler import Handler
|
||||
|
||||
|
||||
class PollHandler(Handler):
|
||||
class PollHandler(Handler[Update]):
|
||||
"""Handler class to handle Telegram updates that contain a poll.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
@@ -80,13 +68,25 @@ class PollHandler(Handler):
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def check_update(self, update: HandlerArg) -> bool:
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -18,27 +18,15 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the PreCheckoutQueryHandler class."""
|
||||
|
||||
|
||||
from telegram import Update
|
||||
from telegram.utils.types import HandlerArg
|
||||
|
||||
from .handler import Handler
|
||||
|
||||
|
||||
class PreCheckoutQueryHandler(Handler):
|
||||
class PreCheckoutQueryHandler(Handler[Update]):
|
||||
"""Handler class to handle Telegram PreCheckout callback queries.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
@@ -80,13 +68,25 @@ class PreCheckoutQueryHandler(Handler):
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def check_update(self, update: HandlerArg) -> bool:
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -20,11 +20,11 @@
|
||||
"""This module contains the RegexHandler class."""
|
||||
|
||||
import warnings
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Pattern, TypeVar, Union
|
||||
from typing import TYPE_CHECKING, Callable, Dict, Optional, Pattern, TypeVar, Union, Any
|
||||
|
||||
from telegram import Update
|
||||
from telegram.ext import Filters, MessageHandler
|
||||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
||||
from telegram.utils.types import HandlerArg
|
||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -40,23 +40,6 @@ class RegexHandler(MessageHandler):
|
||||
module for more information. The ``re.match`` function is used to determine if an update should
|
||||
be handled by this handler.
|
||||
|
||||
Attributes:
|
||||
pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the
|
||||
callback function.
|
||||
pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to
|
||||
the callback function.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Note:
|
||||
This handler is being deprecated. For the same use case use:
|
||||
``MessageHandler(Filters.regex(r'pattern'), callback)``
|
||||
@@ -106,12 +89,29 @@ class RegexHandler(MessageHandler):
|
||||
Raises:
|
||||
ValueError
|
||||
|
||||
Attributes:
|
||||
pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the
|
||||
callback function.
|
||||
pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to
|
||||
the callback function.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
pattern: Union[str, Pattern],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
callback: Callable[[Update, 'CallbackContext'], RT],
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
@@ -147,9 +147,9 @@ class RegexHandler(MessageHandler):
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
update: Update = None,
|
||||
check_result: Optional[Union[bool, Dict[str, Any]]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
) -> Dict[str, object]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if isinstance(check_result, dict):
|
||||
if self.pass_groups:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -18,27 +18,14 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the ShippingQueryHandler class."""
|
||||
|
||||
from telegram import Update
|
||||
from telegram.utils.types import HandlerArg
|
||||
|
||||
from telegram import Update
|
||||
from .handler import Handler
|
||||
|
||||
|
||||
class ShippingQueryHandler(Handler):
|
||||
class ShippingQueryHandler(Handler[Update]):
|
||||
"""Handler class to handle Telegram shipping callback queries.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
@@ -80,13 +67,25 @@ class ShippingQueryHandler(Handler):
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def check_update(self, update: HandlerArg) -> bool:
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -18,9 +18,8 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the StringCommandHandler class."""
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, TypeVar, Union
|
||||
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, TypeVar, Union
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||
|
||||
from .handler import Handler
|
||||
@@ -31,7 +30,7 @@ if TYPE_CHECKING:
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class StringCommandHandler(Handler):
|
||||
class StringCommandHandler(Handler[str]):
|
||||
"""Handler class to handle string commands. Commands are string updates that start with ``/``.
|
||||
|
||||
Note:
|
||||
@@ -42,17 +41,6 @@ class StringCommandHandler(Handler):
|
||||
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
|
||||
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
|
||||
|
||||
Attributes:
|
||||
command (:obj:`str`): The command this handler should listen for.
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_args (:obj:`bool`): Determines whether the handler should be passed
|
||||
``args``.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Args:
|
||||
command (:obj:`str`): The command this handler should listen for.
|
||||
callback (:obj:`callable`): The callback function for this handler. Will be called when
|
||||
@@ -81,12 +69,23 @@ class StringCommandHandler(Handler):
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
command (:obj:`str`): The command this handler should listen for.
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_args (:obj:`bool`): Determines whether the handler should be passed
|
||||
``args``.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
command: str,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
callback: Callable[[str, 'CallbackContext'], RT],
|
||||
pass_args: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
@@ -101,11 +100,11 @@ class StringCommandHandler(Handler):
|
||||
self.command = command
|
||||
self.pass_args = pass_args
|
||||
|
||||
def check_update(self, update: HandlerArg) -> Optional[List[str]]:
|
||||
def check_update(self, update: object) -> Optional[List[str]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:obj:`str`): An incoming command.
|
||||
update (:obj:`object`): The incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
@@ -120,9 +119,9 @@ class StringCommandHandler(Handler):
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
update: str = None,
|
||||
check_result: Optional[List[str]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
) -> Dict[str, object]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pass_args:
|
||||
optional_args['args'] = check_result
|
||||
@@ -131,7 +130,7 @@ class StringCommandHandler(Handler):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
update: str,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[List[str]],
|
||||
) -> None:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -19,9 +19,8 @@
|
||||
"""This module contains the StringRegexHandler class."""
|
||||
|
||||
import re
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, Match, Optional, Pattern, TypeVar, Union
|
||||
from typing import TYPE_CHECKING, Callable, Dict, Match, Optional, Pattern, TypeVar, Union
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||
|
||||
from .handler import Handler
|
||||
@@ -32,7 +31,7 @@ if TYPE_CHECKING:
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class StringRegexHandler(Handler):
|
||||
class StringRegexHandler(Handler[str]):
|
||||
"""Handler class to handle string updates based on a regex which checks the update content.
|
||||
|
||||
Read the documentation of the ``re`` module for more information. The ``re.match`` function is
|
||||
@@ -46,19 +45,6 @@ class StringRegexHandler(Handler):
|
||||
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
|
||||
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
|
||||
|
||||
Attributes:
|
||||
pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the
|
||||
callback function.
|
||||
pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to
|
||||
the callback function.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Args:
|
||||
pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
|
||||
callback (:obj:`callable`): The callback function for this handler. Will be called when
|
||||
@@ -90,12 +76,25 @@ class StringRegexHandler(Handler):
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the
|
||||
callback function.
|
||||
pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to
|
||||
the callback function.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
pattern: Union[str, Pattern],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
callback: Callable[[str, 'CallbackContext'], RT],
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
@@ -116,11 +115,11 @@ class StringRegexHandler(Handler):
|
||||
self.pass_groups = pass_groups
|
||||
self.pass_groupdict = pass_groupdict
|
||||
|
||||
def check_update(self, update: HandlerArg) -> Optional[Match]:
|
||||
def check_update(self, update: object) -> Optional[Match]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:obj:`str`): An incoming command.
|
||||
update (:obj:`object`): The incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
@@ -135,9 +134,9 @@ class StringRegexHandler(Handler):
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
update: str = None,
|
||||
check_result: Optional[Match] = None,
|
||||
) -> Dict[str, Any]:
|
||||
) -> Dict[str, object]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pattern:
|
||||
if self.pass_groups and check_result:
|
||||
@@ -149,7 +148,7 @@ class StringRegexHandler(Handler):
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
update: str,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Match],
|
||||
) -> None:
|
||||
|
||||
+18
-17
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -18,7 +18,7 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the TypeHandler class."""
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Callable, Type, TypeVar, Union
|
||||
from typing import TYPE_CHECKING, Callable, Type, TypeVar, Union
|
||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||
|
||||
from .handler import Handler
|
||||
@@ -27,21 +27,12 @@ if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext
|
||||
|
||||
RT = TypeVar('RT')
|
||||
UT = TypeVar('UT')
|
||||
|
||||
|
||||
class TypeHandler(Handler):
|
||||
class TypeHandler(Handler[UT]):
|
||||
"""Handler class to handle updates of custom types.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`type`): The ``type`` of updates this handler should process.
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
strict (:obj:`bool`): Use ``type`` instead of ``isinstance``. Default is :obj:`False`.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Warning:
|
||||
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
|
||||
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
|
||||
@@ -72,12 +63,22 @@ class TypeHandler(Handler):
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`type`): The ``type`` of updates this handler should process.
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
strict (:obj:`bool`): Use ``type`` instead of ``isinstance``. Default is :obj:`False`.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: Type, # pylint: disable=W0622
|
||||
callback: Callable[[Any, 'CallbackContext'], RT],
|
||||
type: Type[UT], # pylint: disable=W0622
|
||||
callback: Callable[[UT, 'CallbackContext'], RT],
|
||||
strict: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
@@ -92,11 +93,11 @@ class TypeHandler(Handler):
|
||||
self.type = type
|
||||
self.strict = strict
|
||||
|
||||
def check_update(self, update: Any) -> bool:
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
update (:obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
+134
-83
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -33,7 +33,7 @@ from telegram.ext import Dispatcher, JobQueue
|
||||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
||||
from telegram.utils.helpers import get_signal_name
|
||||
from telegram.utils.request import Request
|
||||
from telegram.utils.webhookhandler import WebhookAppClass, WebhookServer
|
||||
from telegram.ext.utils.webhookhandler import WebhookAppClass, WebhookServer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import BasePersistence, Defaults
|
||||
@@ -50,19 +50,10 @@ class Updater:
|
||||
production, use a webhook to receive updates. This is achieved using the WebhookServer and
|
||||
WebhookHandler classes.
|
||||
|
||||
|
||||
Attributes:
|
||||
bot (:class:`telegram.Bot`): The bot used with this Updater.
|
||||
user_sig_handler (:obj:`function`): Optional. Function to be called when a signal is
|
||||
received.
|
||||
update_queue (:obj:`Queue`): Queue for the updates.
|
||||
job_queue (:class:`telegram.ext.JobQueue`): Jobqueue for the updater.
|
||||
dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that handles the updates and
|
||||
dispatches them to the handlers.
|
||||
running (:obj:`bool`): Indicates if the updater is running.
|
||||
persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to
|
||||
store data that should be persistent over restarts.
|
||||
use_context (:obj:`bool`): Optional. :obj:`True` if using context based callbacks.
|
||||
Note:
|
||||
* You must supply either a :attr:`bot` or a :attr:`token` argument.
|
||||
* If you supply a :attr:`bot`, you will need to pass :attr:`defaults` to *both* the bot and
|
||||
the :class:`telegram.ext.Updater`.
|
||||
|
||||
Args:
|
||||
token (:obj:`str`, optional): The bot's token given by the @BotFather.
|
||||
@@ -95,14 +86,23 @@ class Updater:
|
||||
defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to
|
||||
be used if not set explicitly in the bot methods.
|
||||
|
||||
Note:
|
||||
* You must supply either a :attr:`bot` or a :attr:`token` argument.
|
||||
* If you supply a :attr:`bot`, you will need to pass :attr:`defaults` to *both* the bot and
|
||||
the :class:`telegram.ext.Updater`.
|
||||
|
||||
Raises:
|
||||
ValueError: If both :attr:`token` and :attr:`bot` are passed or none of them.
|
||||
|
||||
|
||||
Attributes:
|
||||
bot (:class:`telegram.Bot`): The bot used with this Updater.
|
||||
user_sig_handler (:obj:`function`): Optional. Function to be called when a signal is
|
||||
received.
|
||||
update_queue (:obj:`Queue`): Queue for the updates.
|
||||
job_queue (:class:`telegram.ext.JobQueue`): Jobqueue for the updater.
|
||||
dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that handles the updates and
|
||||
dispatches them to the handlers.
|
||||
running (:obj:`bool`): Indicates if the updater is running.
|
||||
persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to
|
||||
store data that should be persistent over restarts.
|
||||
use_context (:obj:`bool`): Optional. :obj:`True` if using context based callbacks.
|
||||
|
||||
"""
|
||||
|
||||
_request = None
|
||||
@@ -219,7 +219,7 @@ class Updater:
|
||||
self.__lock = Lock()
|
||||
self.__threads: List[Thread] = []
|
||||
|
||||
def _init_thread(self, target: Callable, name: str, *args: Any, **kwargs: Any) -> None:
|
||||
def _init_thread(self, target: Callable, name: str, *args: object, **kwargs: object) -> None:
|
||||
thr = Thread(
|
||||
target=self._thread_wrapper,
|
||||
name=f"Bot:{self.bot.id}:{name}",
|
||||
@@ -229,7 +229,7 @@ class Updater:
|
||||
thr.start()
|
||||
self.__threads.append(thr)
|
||||
|
||||
def _thread_wrapper(self, target: Callable, *args: Any, **kwargs: Any) -> None:
|
||||
def _thread_wrapper(self, target: Callable, *args: object, **kwargs: object) -> None:
|
||||
thr_name = current_thread().name
|
||||
self.logger.debug('%s - started', thr_name)
|
||||
try:
|
||||
@@ -244,36 +244,56 @@ class Updater:
|
||||
self,
|
||||
poll_interval: float = 0.0,
|
||||
timeout: float = 10,
|
||||
clean: bool = False,
|
||||
clean: bool = None,
|
||||
bootstrap_retries: int = -1,
|
||||
read_latency: float = 2.0,
|
||||
allowed_updates: List[str] = None,
|
||||
drop_pending_updates: bool = None,
|
||||
) -> Optional[Queue]:
|
||||
"""Starts polling updates from Telegram.
|
||||
|
||||
Args:
|
||||
poll_interval (:obj:`float`, optional): Time to wait between polling updates from
|
||||
Telegram in seconds. Default is 0.0.
|
||||
timeout (:obj:`float`, optional): Passed to :attr:`telegram.Bot.get_updates`.
|
||||
clean (:obj:`bool`, optional): Whether to clean any pending updates on Telegram servers
|
||||
before actually starting to poll. Default is :obj:`False`.
|
||||
timeout (:obj:`float`, optional): Passed to :meth:`telegram.Bot.get_updates`.
|
||||
drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on
|
||||
Telegram servers before actually starting to poll. Default is :obj:`False`.
|
||||
|
||||
.. versionadded :: 13.4
|
||||
clean (:obj:`bool`, optional): Alias for ``drop_pending_updates``.
|
||||
|
||||
.. deprecated:: 13.4
|
||||
Use ``drop_pending_updates`` instead.
|
||||
bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the
|
||||
`Updater` will retry on failures on the Telegram server.
|
||||
:class:`telegram.ext.Updater` will retry on failures on the Telegram server.
|
||||
|
||||
* < 0 - retry indefinitely (default)
|
||||
* 0 - no retries
|
||||
* > 0 - retry up to X times
|
||||
|
||||
allowed_updates (List[:obj:`str`], optional): Passed to
|
||||
:attr:`telegram.Bot.get_updates`.
|
||||
:meth:`telegram.Bot.get_updates`.
|
||||
read_latency (:obj:`float` | :obj:`int`, optional): Grace time in seconds for receiving
|
||||
the reply from server. Will be added to the `timeout` value and used as the read
|
||||
the reply from server. Will be added to the ``timeout`` value and used as the read
|
||||
timeout from server (Default: 2).
|
||||
|
||||
Returns:
|
||||
:obj:`Queue`: The update queue that can be filled from the main thread.
|
||||
|
||||
"""
|
||||
if (clean is not None) and (drop_pending_updates is not None):
|
||||
raise TypeError('`clean` and `drop_pending_updates` are mutually exclusive.')
|
||||
|
||||
if clean is not None:
|
||||
warnings.warn(
|
||||
'The argument `clean` of `start_polling` is deprecated. Please use '
|
||||
'`drop_pending_updates` instead.',
|
||||
category=TelegramDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
drop_pending_updates = drop_pending_updates if drop_pending_updates is not None else clean
|
||||
|
||||
with self.__lock:
|
||||
if not self.running:
|
||||
self.running = True
|
||||
@@ -290,7 +310,7 @@ class Updater:
|
||||
timeout,
|
||||
read_latency,
|
||||
bootstrap_retries,
|
||||
clean,
|
||||
drop_pending_updates,
|
||||
allowed_updates,
|
||||
ready=polling_ready,
|
||||
)
|
||||
@@ -310,18 +330,20 @@ class Updater:
|
||||
url_path: str = '',
|
||||
cert: str = None,
|
||||
key: str = None,
|
||||
clean: bool = False,
|
||||
clean: bool = None,
|
||||
bootstrap_retries: int = 0,
|
||||
webhook_url: str = None,
|
||||
allowed_updates: List[str] = None,
|
||||
force_event_loop: bool = False,
|
||||
drop_pending_updates: bool = None,
|
||||
ip_address: str = None,
|
||||
) -> Optional[Queue]:
|
||||
"""
|
||||
Starts a small http server to listen for updates via webhook. If cert
|
||||
and key are not provided, the webhook will be started directly on
|
||||
http://listen:port/url_path, so SSL can be handled by another
|
||||
application. Else, the webhook will be started on
|
||||
https://listen:port/url_path
|
||||
https://listen:port/url_path. Also calls :meth:`telegram.Bot.set_webhook` as required.
|
||||
|
||||
Note:
|
||||
Due to an incompatibility of the Tornado library PTB uses for the webhook with Python
|
||||
@@ -338,19 +360,29 @@ class Updater:
|
||||
url_path (:obj:`str`, optional): Path inside url.
|
||||
cert (:obj:`str`, optional): Path to the SSL certificate file.
|
||||
key (:obj:`str`, optional): Path to the SSL key file.
|
||||
clean (:obj:`bool`, optional): Whether to clean any pending updates on Telegram servers
|
||||
before actually starting the webhook. Default is :obj:`False`.
|
||||
drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on
|
||||
Telegram servers before actually starting to poll. Default is :obj:`False`.
|
||||
|
||||
.. versionadded :: 13.4
|
||||
clean (:obj:`bool`, optional): Alias for ``drop_pending_updates``.
|
||||
|
||||
.. deprecated:: 13.4
|
||||
Use ``drop_pending_updates`` instead.
|
||||
bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the
|
||||
`Updater` will retry on failures on the Telegram server.
|
||||
:class:`telegram.ext.Updater` will retry on failures on the Telegram server.
|
||||
|
||||
* < 0 - retry indefinitely (default)
|
||||
* 0 - no retries
|
||||
* > 0 - retry up to X times
|
||||
|
||||
webhook_url (:obj:`str`, optional): Explicitly specify the webhook url. Useful behind
|
||||
NAT, reverse proxy, etc. Default is derived from `listen`, `port` & `url_path`.
|
||||
NAT, reverse proxy, etc. Default is derived from ``listen``, ``port`` &
|
||||
``url_path``.
|
||||
ip_address (:obj:`str`, optional): Passed to :meth:`telegram.Bot.set_webhook`.
|
||||
|
||||
.. versionadded :: 13.4
|
||||
allowed_updates (List[:obj:`str`], optional): Passed to
|
||||
:attr:`telegram.Bot.set_webhook`.
|
||||
:meth:`telegram.Bot.set_webhook`.
|
||||
force_event_loop (:obj:`bool`, optional): Force using the current event loop. See above
|
||||
note for details. Defaults to :obj:`False`
|
||||
|
||||
@@ -358,6 +390,19 @@ class Updater:
|
||||
:obj:`Queue`: The update queue that can be filled from the main thread.
|
||||
|
||||
"""
|
||||
if (clean is not None) and (drop_pending_updates is not None):
|
||||
raise TypeError('`clean` and `drop_pending_updates` are mutually exclusive.')
|
||||
|
||||
if clean is not None:
|
||||
warnings.warn(
|
||||
'The argument `clean` of `start_webhook` is deprecated. Please use '
|
||||
'`drop_pending_updates` instead.',
|
||||
category=TelegramDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
drop_pending_updates = drop_pending_updates if drop_pending_updates is not None else clean
|
||||
|
||||
with self.__lock:
|
||||
if not self.running:
|
||||
self.running = True
|
||||
@@ -376,11 +421,12 @@ class Updater:
|
||||
cert,
|
||||
key,
|
||||
bootstrap_retries,
|
||||
clean,
|
||||
drop_pending_updates,
|
||||
webhook_url,
|
||||
allowed_updates,
|
||||
ready=webhook_ready,
|
||||
force_event_loop=force_event_loop,
|
||||
ip_address=ip_address,
|
||||
)
|
||||
|
||||
self.logger.debug('Waiting for Dispatcher and Webhook to start')
|
||||
@@ -398,7 +444,7 @@ class Updater:
|
||||
timeout,
|
||||
read_latency,
|
||||
bootstrap_retries,
|
||||
clean,
|
||||
drop_pending_updates,
|
||||
allowed_updates,
|
||||
ready=None,
|
||||
): # pragma: no cover
|
||||
@@ -408,7 +454,12 @@ class Updater:
|
||||
|
||||
self.logger.debug('Updater thread started (polling)')
|
||||
|
||||
self._bootstrap(bootstrap_retries, clean=clean, webhook_url='', allowed_updates=None)
|
||||
self._bootstrap(
|
||||
bootstrap_retries,
|
||||
drop_pending_updates=drop_pending_updates,
|
||||
webhook_url='',
|
||||
allowed_updates=None,
|
||||
)
|
||||
|
||||
self.logger.debug('Bootstrap done')
|
||||
|
||||
@@ -504,14 +555,20 @@ class Updater:
|
||||
cert,
|
||||
key,
|
||||
bootstrap_retries,
|
||||
clean,
|
||||
drop_pending_updates,
|
||||
webhook_url,
|
||||
allowed_updates,
|
||||
ready=None,
|
||||
force_event_loop=False,
|
||||
ip_address=None,
|
||||
):
|
||||
self.logger.debug('Updater thread started (webhook)')
|
||||
|
||||
# Note that we only use the SSL certificate for the WebhookServer, if the key is also
|
||||
# present. This is because the WebhookServer may not actually be in charge of performing
|
||||
# the SSL handshake, e.g. in case a reverse proxy is used
|
||||
use_ssl = cert is not None and key is not None
|
||||
|
||||
if not url_path.startswith('/'):
|
||||
url_path = f'/{url_path}'
|
||||
|
||||
@@ -532,23 +589,18 @@ class Updater:
|
||||
# Create and start server
|
||||
self.httpd = WebhookServer(listen, port, app, ssl_ctx)
|
||||
|
||||
if use_ssl:
|
||||
# DO NOT CHANGE: Only set webhook if SSL is handled by library
|
||||
if not webhook_url:
|
||||
webhook_url = self._gen_webhook_url(listen, port, url_path)
|
||||
if not webhook_url:
|
||||
webhook_url = self._gen_webhook_url(listen, port, url_path)
|
||||
|
||||
self._bootstrap(
|
||||
max_retries=bootstrap_retries,
|
||||
clean=clean,
|
||||
webhook_url=webhook_url,
|
||||
cert=open(cert, 'rb'),
|
||||
allowed_updates=allowed_updates,
|
||||
)
|
||||
elif clean:
|
||||
self.logger.warning(
|
||||
"cleaning updates is not supported if "
|
||||
"SSL-termination happens elsewhere; skipping"
|
||||
)
|
||||
# We pass along the cert to the webhook if present.
|
||||
self._bootstrap(
|
||||
max_retries=bootstrap_retries,
|
||||
drop_pending_updates=drop_pending_updates,
|
||||
webhook_url=webhook_url,
|
||||
allowed_updates=allowed_updates,
|
||||
cert=open(cert, 'rb') if cert is not None else None,
|
||||
ip_address=ip_address,
|
||||
)
|
||||
|
||||
self.httpd.serve_forever(force_event_loop=force_event_loop, ready=ready)
|
||||
|
||||
@@ -558,24 +610,34 @@ class Updater:
|
||||
|
||||
@no_type_check
|
||||
def _bootstrap(
|
||||
self, max_retries, clean, webhook_url, allowed_updates, cert=None, bootstrap_interval=5
|
||||
self,
|
||||
max_retries,
|
||||
drop_pending_updates,
|
||||
webhook_url,
|
||||
allowed_updates,
|
||||
cert=None,
|
||||
bootstrap_interval=5,
|
||||
ip_address=None,
|
||||
):
|
||||
retries = [0]
|
||||
|
||||
def bootstrap_del_webhook():
|
||||
self.bot.delete_webhook()
|
||||
return False
|
||||
|
||||
def bootstrap_clean_updates():
|
||||
self.logger.debug('Cleaning updates from Telegram server')
|
||||
updates = self.bot.get_updates()
|
||||
while updates:
|
||||
updates = self.bot.get_updates(updates[-1].update_id + 1)
|
||||
self.logger.debug('Deleting webhook')
|
||||
if drop_pending_updates:
|
||||
self.logger.debug('Dropping pending updates from Telegram server')
|
||||
self.bot.delete_webhook(drop_pending_updates=drop_pending_updates)
|
||||
return False
|
||||
|
||||
def bootstrap_set_webhook():
|
||||
self.logger.debug('Setting webhook')
|
||||
if drop_pending_updates:
|
||||
self.logger.debug('Dropping pending updates from Telegram server')
|
||||
self.bot.set_webhook(
|
||||
url=webhook_url, certificate=cert, allowed_updates=allowed_updates
|
||||
url=webhook_url,
|
||||
certificate=cert,
|
||||
allowed_updates=allowed_updates,
|
||||
ip_address=ip_address,
|
||||
drop_pending_updates=drop_pending_updates,
|
||||
)
|
||||
return False
|
||||
|
||||
@@ -589,11 +651,11 @@ class Updater:
|
||||
self.logger.error('Failed bootstrap phase after %s retries (%s)', retries[0], exc)
|
||||
raise exc
|
||||
|
||||
# Cleaning pending messages is done by polling for them - so we need to delete webhook if
|
||||
# one is configured.
|
||||
# We also take this chance to delete pre-configured webhook if this is a polling Updater.
|
||||
# NOTE: We don't know ahead if a webhook is configured, so we just delete.
|
||||
if clean or not webhook_url:
|
||||
# Dropping pending updates from TG can be efficiently done with the drop_pending_updates
|
||||
# parameter of delete/start_webhook, even in the case of polling. Also we want to make
|
||||
# sure that no webhook is configured in case of polling, so we just always call
|
||||
# delete_webhook for polling
|
||||
if drop_pending_updates or not webhook_url:
|
||||
self._network_loop_retry(
|
||||
bootstrap_del_webhook,
|
||||
bootstrap_onerr_cb,
|
||||
@@ -602,17 +664,6 @@ class Updater:
|
||||
)
|
||||
retries[0] = 0
|
||||
|
||||
# Clean pending messages, if requested.
|
||||
if clean:
|
||||
self._network_loop_retry(
|
||||
bootstrap_clean_updates,
|
||||
bootstrap_onerr_cb,
|
||||
'bootstrap clean updates',
|
||||
bootstrap_interval,
|
||||
)
|
||||
retries[0] = 0
|
||||
sleep(1)
|
||||
|
||||
# Restore/set webhook settings, if needed. Again, we don't know ahead if a webhook is set,
|
||||
# so we set it anyhow.
|
||||
if webhook_url:
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2021
|
||||
# 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/].
|
||||
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the Promise class."""
|
||||
|
||||
import logging
|
||||
from threading import Event
|
||||
from typing import Callable, List, Optional, Tuple, TypeVar, Union
|
||||
|
||||
from telegram.utils.types import JSONDict
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Promise:
|
||||
"""A simple Promise implementation for use with the run_async decorator, DelayQueue etc.
|
||||
|
||||
Args:
|
||||
pooled_function (:obj:`callable`): The callable that will be called concurrently.
|
||||
args (:obj:`list` | :obj:`tuple`): Positional arguments for :attr:`pooled_function`.
|
||||
kwargs (:obj:`dict`): Keyword arguments for :attr:`pooled_function`.
|
||||
update (:class:`telegram.Update` | :obj:`object`, optional): The update this promise is
|
||||
associated with.
|
||||
error_handling (:obj:`bool`, optional): Whether exceptions raised by :attr:`func`
|
||||
may be handled by error handlers. Defaults to :obj:`True`.
|
||||
|
||||
Attributes:
|
||||
pooled_function (:obj:`callable`): The callable that will be called concurrently.
|
||||
args (:obj:`list` | :obj:`tuple`): Positional arguments for :attr:`pooled_function`.
|
||||
kwargs (:obj:`dict`): Keyword arguments for :attr:`pooled_function`.
|
||||
done (:obj:`threading.Event`): Is set when the result is available.
|
||||
update (:class:`telegram.Update` | :obj:`object`): Optional. The update this promise is
|
||||
associated with.
|
||||
error_handling (:obj:`bool`): Optional. Whether exceptions raised by :attr:`func`
|
||||
may be handled by error handlers. Defaults to :obj:`True`.
|
||||
|
||||
"""
|
||||
|
||||
# TODO: Remove error_handling parameter once we drop the @run_async decorator
|
||||
def __init__(
|
||||
self,
|
||||
pooled_function: Callable[..., RT],
|
||||
args: Union[List, Tuple],
|
||||
kwargs: JSONDict,
|
||||
update: object = None,
|
||||
error_handling: bool = True,
|
||||
):
|
||||
self.pooled_function = pooled_function
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
self.update = update
|
||||
self.error_handling = error_handling
|
||||
self.done = Event()
|
||||
self._result: Optional[RT] = None
|
||||
self._exception: Optional[Exception] = None
|
||||
|
||||
def run(self) -> None:
|
||||
"""Calls the :attr:`pooled_function` callable."""
|
||||
|
||||
try:
|
||||
self._result = self.pooled_function(*self.args, **self.kwargs)
|
||||
|
||||
except Exception as exc:
|
||||
self._exception = exc
|
||||
|
||||
finally:
|
||||
self.done.set()
|
||||
|
||||
def __call__(self) -> None:
|
||||
self.run()
|
||||
|
||||
def result(self, timeout: float = None) -> Optional[RT]:
|
||||
"""Return the result of the ``Promise``.
|
||||
|
||||
Args:
|
||||
timeout (:obj:`float`, optional): Maximum time in seconds to wait for the result to be
|
||||
calculated. ``None`` means indefinite. Default is ``None``.
|
||||
|
||||
Returns:
|
||||
Returns the return value of :attr:`pooled_function` or ``None`` if the ``timeout``
|
||||
expires.
|
||||
|
||||
Raises:
|
||||
object exception raised by :attr:`pooled_function`.
|
||||
"""
|
||||
self.done.wait(timeout=timeout)
|
||||
if self._exception is not None:
|
||||
raise self._exception # pylint: disable=raising-bad-type
|
||||
return self._result
|
||||
|
||||
@property
|
||||
def exception(self) -> Optional[Exception]:
|
||||
"""The exception raised by :attr:`pooled_function` or ``None`` if no exception has been
|
||||
raised (yet)."""
|
||||
return self._exception
|
||||
@@ -0,0 +1,208 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2021
|
||||
# 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=C0114
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from queue import Queue
|
||||
from ssl import SSLContext
|
||||
from threading import Event, Lock
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
import tornado.web
|
||||
from tornado import httputil
|
||||
from tornado.httpserver import HTTPServer
|
||||
from tornado.ioloop import IOLoop
|
||||
|
||||
from telegram import Update
|
||||
from telegram.utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ImportError:
|
||||
import json # type: ignore[no-redef]
|
||||
|
||||
|
||||
class WebhookServer:
|
||||
def __init__(
|
||||
self, listen: str, port: int, webhook_app: 'WebhookAppClass', ssl_ctx: SSLContext
|
||||
):
|
||||
self.http_server = HTTPServer(webhook_app, ssl_options=ssl_ctx)
|
||||
self.listen = listen
|
||||
self.port = port
|
||||
self.loop: Optional[IOLoop] = None
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.is_running = False
|
||||
self.server_lock = Lock()
|
||||
self.shutdown_lock = Lock()
|
||||
|
||||
def serve_forever(self, force_event_loop: bool = False, ready: Event = None) -> None:
|
||||
with self.server_lock:
|
||||
self.is_running = True
|
||||
self.logger.debug('Webhook Server started.')
|
||||
self._ensure_event_loop(force_event_loop=force_event_loop)
|
||||
self.loop = IOLoop.current()
|
||||
self.http_server.listen(self.port, address=self.listen)
|
||||
|
||||
if ready is not None:
|
||||
ready.set()
|
||||
|
||||
self.loop.start()
|
||||
self.logger.debug('Webhook Server stopped.')
|
||||
self.is_running = False
|
||||
|
||||
def shutdown(self) -> None:
|
||||
with self.shutdown_lock:
|
||||
if not self.is_running:
|
||||
self.logger.warning('Webhook Server already stopped.')
|
||||
return
|
||||
self.loop.add_callback(self.loop.stop) # type: ignore
|
||||
|
||||
def handle_error(self, request: object, client_address: str) -> None: # pylint: disable=W0613
|
||||
"""Handle an error gracefully."""
|
||||
self.logger.debug(
|
||||
'Exception happened during processing of request from %s',
|
||||
client_address,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
def _ensure_event_loop(self, force_event_loop: bool = False) -> None:
|
||||
"""If there's no asyncio event loop set for the current thread - create one."""
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
if (
|
||||
not force_event_loop
|
||||
and os.name == 'nt'
|
||||
and sys.version_info >= (3, 8)
|
||||
and isinstance(loop, asyncio.ProactorEventLoop) # type: ignore[attr-defined]
|
||||
):
|
||||
raise TypeError(
|
||||
'`ProactorEventLoop` is incompatible with '
|
||||
'Tornado. Please switch to `SelectorEventLoop`.'
|
||||
)
|
||||
except RuntimeError:
|
||||
# Python 3.8 changed default asyncio event loop implementation on windows
|
||||
# from SelectorEventLoop to ProactorEventLoop. At the time of this writing
|
||||
# Tornado doesn't support ProactorEventLoop and suggests that end users
|
||||
# change asyncio event loop policy to WindowsSelectorEventLoopPolicy.
|
||||
# https://github.com/tornadoweb/tornado/issues/2608
|
||||
# To avoid changing the global event loop policy, we manually construct
|
||||
# a SelectorEventLoop instance instead of using asyncio.new_event_loop().
|
||||
# Note that the fix is not applied in the main thread, as that can break
|
||||
# user code in even more ways than changing the global event loop policy can,
|
||||
# and because Updater always starts its webhook server in a separate thread.
|
||||
# Ideally, we would want to check that Tornado actually raises the expected
|
||||
# NotImplementedError, but it's not possible to cleanly recover from that
|
||||
# exception in current Tornado version.
|
||||
if (
|
||||
os.name == 'nt'
|
||||
and sys.version_info >= (3, 8)
|
||||
# OS+version check makes hasattr check redundant, but just to be sure
|
||||
and hasattr(asyncio, 'WindowsProactorEventLoopPolicy')
|
||||
and (
|
||||
isinstance(
|
||||
asyncio.get_event_loop_policy(),
|
||||
asyncio.WindowsProactorEventLoopPolicy, # type: ignore # pylint: disable
|
||||
)
|
||||
)
|
||||
): # pylint: disable=E1101
|
||||
self.logger.debug(
|
||||
'Applying Tornado asyncio event loop fix for Python 3.8+ on Windows'
|
||||
)
|
||||
loop = asyncio.SelectorEventLoop()
|
||||
else:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
|
||||
class WebhookAppClass(tornado.web.Application):
|
||||
def __init__(self, webhook_path: str, bot: 'Bot', update_queue: Queue):
|
||||
self.shared_objects = {"bot": bot, "update_queue": update_queue}
|
||||
handlers = [(rf"{webhook_path}/?", WebhookHandler, self.shared_objects)] # noqa
|
||||
tornado.web.Application.__init__(self, handlers) # type: ignore
|
||||
|
||||
def log_request(self, handler: tornado.web.RequestHandler) -> None:
|
||||
pass
|
||||
|
||||
|
||||
# WebhookHandler, process webhook calls
|
||||
# pylint: disable=W0223
|
||||
class WebhookHandler(tornado.web.RequestHandler):
|
||||
SUPPORTED_METHODS = ["POST"] # type: ignore
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
application: tornado.web.Application,
|
||||
request: httputil.HTTPServerRequest,
|
||||
**kwargs: JSONDict,
|
||||
):
|
||||
super().__init__(application, request, **kwargs)
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
def initialize(self, bot: 'Bot', update_queue: Queue) -> None:
|
||||
# pylint: disable=W0201
|
||||
self.bot = bot
|
||||
self.update_queue = update_queue
|
||||
|
||||
def set_default_headers(self) -> None:
|
||||
self.set_header("Content-Type", 'application/json; charset="utf-8"')
|
||||
|
||||
def post(self) -> None:
|
||||
self.logger.debug('Webhook triggered')
|
||||
self._validate_post()
|
||||
json_string = self.request.body.decode()
|
||||
data = json.loads(json_string)
|
||||
self.set_status(200)
|
||||
self.logger.debug('Webhook received data: %s', json_string)
|
||||
update = Update.de_json(data, self.bot)
|
||||
if update:
|
||||
self.logger.debug('Received Update with ID %d on Webhook', update.update_id)
|
||||
self.update_queue.put(update)
|
||||
|
||||
def _validate_post(self) -> None:
|
||||
ct_header = self.request.headers.get("Content-Type", None)
|
||||
if ct_header != 'application/json':
|
||||
raise tornado.web.HTTPError(403)
|
||||
|
||||
def write_error(self, status_code: int, **kwargs: Any) -> None:
|
||||
"""Log an arbitrary message.
|
||||
|
||||
This is used by all other logging functions.
|
||||
|
||||
It overrides ``BaseHTTPRequestHandler.log_message``, which logs to ``sys.stderr``.
|
||||
|
||||
The first argument, FORMAT, is a format string for the message to be logged. If the format
|
||||
string contains any % escapes requiring parameters, they should be specified as subsequent
|
||||
arguments (it's just like printf!).
|
||||
|
||||
The client ip is prefixed to every message.
|
||||
|
||||
"""
|
||||
super().write_error(status_code, **kwargs)
|
||||
self.logger.debug(
|
||||
"%s - - %s",
|
||||
self.request.remote_ip,
|
||||
"Exception in WebhookHandler",
|
||||
exc_info=kwargs['exc_info'],
|
||||
)
|
||||
+23
-25
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -20,7 +20,8 @@
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from telegram import PhotoSize, TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.types import JSONDict, ODVInput
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
@@ -32,20 +33,6 @@ class Animation(TelegramObject):
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
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.
|
||||
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.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
@@ -62,6 +49,20 @@ class Animation(TelegramObject):
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): File identifier.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
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.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -104,21 +105,18 @@ class Animation(TelegramObject):
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File':
|
||||
def get_file(
|
||||
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
|
||||
) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
|
||||
|
||||
Args:
|
||||
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
|
||||
the read timeout from the server (instead of the one specified during creation of
|
||||
the connection pool).
|
||||
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
|
||||
Telegram API.
|
||||
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.File`
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
return self.bot.get_file(self.file_id, timeout=timeout, api_kwargs=api_kwargs)
|
||||
return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
+25
-27
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -21,7 +21,8 @@
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from telegram import PhotoSize, TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.types import JSONDict, ODVInput
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
@@ -33,22 +34,6 @@ class Audio(TelegramObject):
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
duration (:obj:`int`): Duration of the audio in seconds.
|
||||
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.
|
||||
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.
|
||||
thumb (:class:`telegram.PhotoSize`): Optional. Thumbnail of the album cover to
|
||||
which the music file belongs.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
@@ -66,6 +51,22 @@ class Audio(TelegramObject):
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
duration (:obj:`int`): Duration of the audio in seconds.
|
||||
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.
|
||||
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.
|
||||
thumb (:class:`telegram.PhotoSize`): Optional. Thumbnail of the album cover to
|
||||
which the music file belongs.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -108,21 +109,18 @@ class Audio(TelegramObject):
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File':
|
||||
def get_file(
|
||||
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
|
||||
) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
|
||||
|
||||
Args:
|
||||
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
|
||||
the read timeout from the server (instead of the one specified during creation of
|
||||
the connection pool).
|
||||
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
|
||||
Telegram API.
|
||||
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.File`
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
return self.bot.get_file(self.file_id, timeout=timeout, api_kwargs=api_kwargs)
|
||||
return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
+31
-32
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -20,6 +20,8 @@
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from telegram import TelegramObject
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.types import JSONDict, ODVInput
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
@@ -32,19 +34,6 @@ class ChatPhoto(TelegramObject):
|
||||
considered equal, if their :attr:`small_file_unique_id` and :attr:`big_file_unique_id` are
|
||||
equal.
|
||||
|
||||
Attributes:
|
||||
small_file_id (:obj:`str`): File identifier of small (160x160) chat photo.
|
||||
This file_id can be used only for photo download and only for as long
|
||||
as the photo is not changed.
|
||||
small_file_unique_id (:obj:`str`): Unique file identifier of small (160x160) chat photo,
|
||||
which is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
big_file_id (:obj:`str`): File identifier of big (640x640) chat photo.
|
||||
This file_id can be used only for photo download and only for as long as
|
||||
the photo is not changed.
|
||||
big_file_unique_id (:obj:`str`): Unique file identifier of big (640x640) chat photo,
|
||||
which is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
Args:
|
||||
small_file_id (:obj:`str`): Unique file identifier of small (160x160) chat photo. This
|
||||
file_id can be used only for photo download and only for as long
|
||||
@@ -60,6 +49,20 @@ class ChatPhoto(TelegramObject):
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
Attributes:
|
||||
small_file_id (:obj:`str`): File identifier of small (160x160) chat photo.
|
||||
This file_id can be used only for photo download and only for as long
|
||||
as the photo is not changed.
|
||||
small_file_unique_id (:obj:`str`): Unique file identifier of small (160x160) chat photo,
|
||||
which is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
big_file_id (:obj:`str`): File identifier of big (640x640) chat photo.
|
||||
This file_id can be used only for photo download and only for as long as
|
||||
the photo is not changed.
|
||||
big_file_unique_id (:obj:`str`): Unique file identifier of big (640x640) chat photo,
|
||||
which is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -83,42 +86,38 @@ class ChatPhoto(TelegramObject):
|
||||
self.big_file_unique_id,
|
||||
)
|
||||
|
||||
def get_small_file(self, timeout: int = None, **kwargs: Any) -> 'File':
|
||||
def get_small_file(
|
||||
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
|
||||
) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the
|
||||
small (160x160) chat photo
|
||||
|
||||
Args:
|
||||
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
|
||||
the read timeout from the server (instead of the one specified during creation of
|
||||
the connection pool).
|
||||
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
|
||||
Telegram API.
|
||||
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.File`
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
return self.bot.get_file(self.small_file_id, timeout=timeout, **kwargs)
|
||||
return self.bot.get_file(
|
||||
file_id=self.small_file_id, timeout=timeout, api_kwargs=api_kwargs
|
||||
)
|
||||
|
||||
def get_big_file(self, timeout: int = None, **kwargs: Any) -> 'File':
|
||||
def get_big_file(
|
||||
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
|
||||
) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the
|
||||
big (640x640) chat photo
|
||||
|
||||
Args:
|
||||
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
|
||||
the read timeout from the server (instead of the one specified during creation of
|
||||
the connection pool).
|
||||
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
|
||||
Telegram API.
|
||||
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.File`
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
return self.bot.get_file(self.big_file_id, timeout=timeout, **kwargs)
|
||||
return self.bot.get_file(file_id=self.big_file_id, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -29,13 +29,6 @@ class Contact(TelegramObject):
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`phone_number` is equal.
|
||||
|
||||
Attributes:
|
||||
phone_number (:obj:`str`): Contact's phone number.
|
||||
first_name (:obj:`str`): Contact's first name.
|
||||
last_name (:obj:`str`): Optional. Contact's last name.
|
||||
user_id (:obj:`int`): Optional. Contact's user identifier in Telegram.
|
||||
vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard.
|
||||
|
||||
Args:
|
||||
phone_number (:obj:`str`): Contact's phone number.
|
||||
first_name (:obj:`str`): Contact's first name.
|
||||
@@ -44,6 +37,13 @@ class Contact(TelegramObject):
|
||||
vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard.
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
Attributes:
|
||||
phone_number (:obj:`str`): Contact's phone number.
|
||||
first_name (:obj:`str`): Contact's first name.
|
||||
last_name (:obj:`str`): Optional. Contact's last name.
|
||||
user_id (:obj:`int`): Optional. Contact's user identifier in Telegram.
|
||||
vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
+20
-22
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -21,7 +21,8 @@
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from telegram import PhotoSize, TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.types import JSONDict, ODVInput
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
@@ -34,17 +35,6 @@ class Document(TelegramObject):
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): File identifier.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
thumb (:class:`telegram.PhotoSize`): Optional. Document thumbnail.
|
||||
file_name (:obj:`str`): Original filename.
|
||||
mime_type (:obj:`str`): Optional. MIME type of the file.
|
||||
file_size (:obj:`int`): Optional. File size.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
@@ -57,6 +47,17 @@ class Document(TelegramObject):
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): File identifier.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
thumb (:class:`telegram.PhotoSize`): Optional. Document thumbnail.
|
||||
file_name (:obj:`str`): Original filename.
|
||||
mime_type (:obj:`str`): Optional. MIME type of the file.
|
||||
file_size (:obj:`int`): Optional. File size.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
"""
|
||||
|
||||
_id_keys = ('file_id',)
|
||||
@@ -95,21 +96,18 @@ class Document(TelegramObject):
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File':
|
||||
def get_file(
|
||||
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
|
||||
) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
|
||||
|
||||
Args:
|
||||
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
|
||||
the read timeout from the server (instead of the one specified during creation of
|
||||
the connection pool).
|
||||
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
|
||||
Telegram API.
|
||||
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.File`
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
return self.bot.get_file(self.file_id, timeout=timeout, api_kwargs=api_kwargs)
|
||||
return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user