Compare commits

...

17 Commits

Author SHA1 Message Date
Hinrich Mahler ccedd3a87d Bump version to v13.4.1 2021-03-14 19:21:44 +01:00
Bibo-Joshi 0bb4be55ac Fix setup.py (#2431) 2021-03-14 19:17:08 +01:00
Hinrich Mahler 21ded420e2 Bump version to v13.4 2021-03-14 17:00:26 +01:00
Bibo-Joshi 7d893fd04b Doc Fixes (#2404)
* Improve some badges for PTB-Raw

* doc fix for add_error_handler

* Some rendering

* Bump sphinx dependency

* Change signature annotation setting

* fix: chat_id can be string, message_id only int

* feat: add RTD link to documentation

* improving sender chat docstring (#2412)

* fix: improving sender chat docstring

also adding a note to a weird edge case

* fix: words being hard

* Add note on donations

* typo

* typo in User.get_profile_pictures docstrings

* Fix: meth, not attr for meth, not attr

* filters + inlinequery doc fix

* Bump versions, update RTD config file

* Try fix build

* Revert "fix: chat_id can be string, message_id only int"

This reverts commit ba04e5aa

* Add Starry & Harshil to credits

Co-authored-by: poolitzer <25934244+Poolitzer@users.noreply.github.com>
Co-authored-by: Harshil <ilovebhagwan@gmail.com>
2021-03-14 16:46:37 +01:00
Bibo-Joshi 7015f8dedc Type Hinting Fixes (#2425)
Co-authored-by: poolitzer <25934244+Poolitzer@users.noreply.github.com>
2021-03-14 16:42:03 +01:00
Poolitzer ac02bce109 API 5.1 (#2424)
* Feat: New invite links

* Fix: doc strings

Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de>

* new dice, new admin privilege, revoke_messages, update and fix some docs

* add missing param to shortcut

* Add ChatMemberUpdated

* Add voicechat related objects

Signed-off-by: starry69 <starry369126@outlook.com>

* add versionadd tags

Signed-off-by: starry69 <starry369126@outlook.com>

* Fix filter tests

* Update tg.Update

* ChatMemberHandler

* Add versioning directives

* add can_manage_voice_chats attr and fix docs

Signed-off-by: starry69 <starry369126@outlook.com>

* fix chat shortcut

Signed-off-by: starry69 <starry369126@outlook.com>

* address review

* MADTC

* Chat.message_auto_delete_time

* Some doc fixes

* address review

Signed-off-by: starry69 <starry369126@outlook.com>

* welp

Signed-off-by: starry69 <starry369126@outlook.com>

* Add voicechat related filters

Signed-off-by: starry69 <starry369126@outlook.com>

* Fix: Addressing review

change place of version adding, added obj:True as doc string, changing how member limit is initiated

* feat: adding chat shortcuts for invite links

* fix: changing equality of chatinviteobjects

* Non-test comments

* Some test fixes

* A bit more tests

* Bump API version in both readmes

* Increase coverage

* Add Bot API Version in telegram.constants (#2429)

* add bot api version in constants

Signed-off-by: starry69 <starry369126@outlook.com>

* addressing review

Signed-off-by: starry69 <starry369126@outlook.com>

* add versioning directive

Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de>

* pre-commit & coverage

Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de>
Co-authored-by: Harshil <ilovebhagwan@gmail.com>
Co-authored-by: starry69 <starry369126@outlook.com>
2021-03-14 16:41:35 +01:00
Bibo-Joshi 3a9a0ab96d Update pre-commit Settings (#2415)
Co-authored-by: Harshil <ilovebhagwan@gmail.com>
2021-03-13 16:21:03 +01:00
Bibo-Joshi aba17cb997 Improve Updater.set_webhook (#2419)
* Get started

* tests

* Some doc fixes

* Some doc fixes
2021-03-13 15:35:26 +01:00
Bibo-Joshi 038a3b4452 Fix Logging for Vendored urllib3 (#2427) 2021-03-13 15:14:10 +01:00
Bibo-Joshi b03ebc5a65 Stabilize Tests (#2409)
* Fix Photo Tests

* Try harder

* Try stabalizing pin&unpin test

* Drop file size tests

* Fix that one failing test …
2021-03-10 16:51:56 +01:00
Hinrich Mahler e9c01c7772 Bump version to v13.3 2021-02-19 19:55:49 +01:00
Bibo-Joshi 552298595c Doc Fixes (#2359)
* Improve some badges for PTB-Raw

* doc fix for add_error_handler

* Some rendering

* Doc fixes for filters.py

* render '@' as code

Co-authored-by: Harshil <ilovebhagwan@gmail.com>
2021-02-19 19:27:17 +01:00
Bibo-Joshi 2a4a0d0ccd Refactor Defaults Integration (#2363)
* Change default handling, update signatures, get existing tests to pass.

* Try running tests on ubuntu 18.04

* Roll back

* Rework check_shortcut_call tests

* Further improve check_shortcut_call tests

* Start on defaults-checks for shortcuts, get it working for test_message

* Add check_shortcut_defaults to all other shortcut tests

* Some fine tuning

* Add defaults checking for bot methods

* Missing tests for TestCallbackQuery

* Test edit_message_media with defaults & some comments

* Fix cryptography requirement

* drop debug prints

* Remove debug prints

* Another try

* Try to fix coverage & logs

* Rearrange test order

* increase coverage

* Try to fix coverage reports

* address review

* Adapt tests like in #2386

* fix CI

* fix CI
2021-02-19 19:07:48 +01:00
Harshil eb993db473 Add Missing telegram.SecureValue to init and Docs (#2398) 2021-02-19 17:46:52 +01:00
Bibo-Joshi c77ef7eef3 Deprecate MessageQueue (#2393) 2021-02-19 17:29:50 +01:00
Bibo-Joshi a34f0b9bee Make cryptography Dependency Optional & Refactor Some Tests (#2386)
* Make cryptography optional

* Try fixing CI

* Try some more

* Update pytest, mypy & pyupgrade, refactor test_meta, hope that things start to work

* Fix filterwarnings

* Mama mia! Here we go again!

* Add stupid debug prints

* A new hope
2021-02-13 22:07:37 +01:00
Bibo-Joshi eee8921598 Update cryptography Dependency (#2370) 2021-02-08 19:28:54 +01:00
146 changed files with 4908 additions and 2134 deletions
+11 -14
View File
@@ -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``.
@@ -109,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
@@ -127,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
@@ -196,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
@@ -256,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
+1 -1
View File
@@ -27,4 +27,4 @@ Hey! You're PRing? Cool! Please have a look at the below checklist. It's here to
- [ ] 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 in `README.rst` and `README_RAW.rst`, including the badge
- [ ] 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 }}
+19 -14
View File
@@ -15,13 +15,6 @@ jobs:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
os: [ubuntu-latest, windows-latest, macos-latest]
include:
- os: ubuntu-latest
python-version: 3.7
test-build: True
- os: windows-latest
python-version: 3.7
test-build: True
fail-fast: False
steps:
- uses: actions/checkout@v2
@@ -40,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
+29 -7
View File
@@ -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,21 +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.7.4
rev: v2.10.0
hooks:
- id: pyupgrade
files: ^(telegram|examples|tests)/.*\.py$
args:
- --py36-plus
- --py36-plus
+17 -5
View File
@@ -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
View File
@@ -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:
+60
View File
@@ -2,6 +2,66 @@
Changelog
=========
Version 13.4.1
==============
*Released 2021-03-14*
**Hot fix release:**
- Fixed a bug in ``setup.py`` (`#2431`_)
.. _`#2431`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2431
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*
-53
View File
@@ -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)"
+17 -2
View File
@@ -20,7 +20,7 @@ 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://img.shields.io/badge/Bot%20API-5.0-blue?logo=telegram
.. 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
@@ -111,7 +111,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
Telegram API support
====================
All types and methods of the Telegram Bot API **5.0** are supported.
All types and methods of the Telegram Bot API **5.1** are supported.
==========
Installing
@@ -137,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
===============
@@ -220,6 +230,11 @@ 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
=======
+20 -6
View File
@@ -13,22 +13,22 @@ We have a vibrant community of developers helping each other in our `Telegram gr
*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/
: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/
:target: https://pypi.org/project/python-telegram-bot-raw/
:alt: Supported Python versions
.. image:: https://img.shields.io/badge/Bot%20API-5.0-blue?logo=telegram
.. 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
:target: https://pypistats.org/packages/python-telegram-bot-raw
:alt: PyPi Package Monthly Download
.. image:: https://img.shields.io/badge/docs-latest-af1a97.svg
.. image:: https://readthedocs.org/projects/python-telegram-bot/badge/?version=stable
:target: https://python-telegram-bot.readthedocs.io/
:alt: Documentation Status
@@ -105,7 +105,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
Telegram API support
====================
All types and methods of the Telegram Bot API **5.0** are supported.
All types and methods of the Telegram Bot API **5.1** are supported.
==========
Installing
@@ -137,6 +137,15 @@ 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
===============
@@ -203,6 +212,11 @@ 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
=======
+2 -2
View File
@@ -1,3 +1,3 @@
sphinx>=1.7.9
sphinx_rtd_theme
sphinx==3.5.2
sphinx_rtd_theme==0.5.1
sphinx-pypi-upload
+6 -3
View File
@@ -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']
@@ -58,9 +61,9 @@ author = u'Leandro Toledo'
# built documents.
#
# The short X.Y version.
version = '13.2' # telegram.__version__[:3]
version = '13.4.1' # telegram.__version__[:3]
# The full version, including alpha/beta/rc tags.
release = '13.2' # telegram.__version__
release = '13.4.1' # telegram.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
+6
View File
@@ -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:
+1
View File
@@ -21,6 +21,7 @@ Handlers
telegram.ext.handler
telegram.ext.callbackqueryhandler
telegram.ext.choseninlineresulthandler
telegram.ext.chatmemberhandler
telegram.ext.commandhandler
telegram.ext.conversationhandler
telegram.ext.inlinequeryhandler
@@ -0,0 +1,6 @@
telegram.MessageAutoDeleteTimerChanged
======================================
.. autoclass:: telegram.MessageAutoDeleteTimerChanged
:members:
:show-inheritance:
+7
View File
@@ -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
+6
View File
@@ -0,0 +1,6 @@
telegram.SecureValue
====================
.. autoclass:: telegram.SecureValue
:members:
:show-inheritance:
+7
View File
@@ -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:
+13 -14
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0613, C0116
# type: ignore[union-attr]
# pylint: disable=C0116
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -37,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(
@@ -50,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(
@@ -62,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.')
@@ -115,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(
+4 -5
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0613, C0116
# type: ignore[union-attr]
# pylint: disable=C0116
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -54,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?",
@@ -72,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
+3 -4
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# 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.
@@ -79,7 +78,7 @@ def deep_linked_level_2(update: Update, context: CallbackContext) -> None:
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.",
@@ -104,7 +103,7 @@ def deep_linked_level_4(update: Update, context: CallbackContext) -> None:
)
def main():
def main() -> None:
"""Start the bot."""
# Create the Updater and pass it your bot's token.
updater = Updater("TOKEN")
+5 -6
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0613, C0116
# type: ignore[union-attr]
# pylint: disable=C0116
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -31,22 +30,22 @@ 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.
updater = Updater("TOKEN")
+8 -8
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0613, C0116
# type: ignore[union-attr]
# pylint: disable=C0116
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -28,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)
@@ -40,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'
@@ -53,19 +53,19 @@ 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.
updater = Updater(BOT_TOKEN)
+9 -8
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0613, C0116
# type: ignore[union-attr]
# pylint: disable=C0116
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -30,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
+5 -6
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0613, C0116
# type: ignore[union-attr]
# pylint: disable=C0116
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -17,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'),
@@ -31,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
@@ -41,11 +40,11 @@ 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.
updater = Updater("TOKEN")
+9 -10
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# 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.
@@ -38,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
@@ -60,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
@@ -81,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()
@@ -98,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()
@@ -115,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()
@@ -133,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()
@@ -150,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
@@ -159,7 +158,7 @@ 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")
+18 -18
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0613, C0116
# type: ignore[union-attr]
# pylint: disable=C0116
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -16,6 +15,7 @@ bot.
"""
import logging
from typing import Tuple, Dict, Any
from telegram import InlineKeyboardMarkup, InlineKeyboardButton, Update
from telegram.ext import (
@@ -64,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 '
@@ -103,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.'
@@ -116,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.'
@@ -151,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()
@@ -169,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 = [
@@ -190,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
@@ -217,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)
@@ -226,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 = [
[
@@ -253,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.'
@@ -264,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
@@ -274,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]
@@ -292,14 +292,14 @@ 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.
updater = Updater("TOKEN")
+12 -13
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0613, C0116
# type: ignore[union-attr]
# pylint: disable=C0116
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -24,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:
@@ -65,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',
@@ -96,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())
+6 -7
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0613, C0116
# type: ignore[union-attr]
# pylint: disable=C0116
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -28,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)
@@ -91,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':
@@ -109,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':
@@ -120,12 +119,12 @@ 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.
updater = Updater("TOKEN")
+15 -15
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0613, C0116, C0103
# type: ignore[union-attr]
# pylint: disable=C0116
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -16,6 +15,7 @@ bot.
"""
import logging
from typing import Dict
from telegram import ReplyKeyboardMarkup, Update
from telegram.ext import (
@@ -46,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():
@@ -55,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 += (
@@ -72,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):
@@ -86,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"'
)
@@ -94,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()
@@ -117,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)
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(
@@ -162,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()
+6 -7
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0613, C0116
# type: ignore[union-attr]
# pylint: disable=C0116
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -35,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'
@@ -121,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())]]
@@ -132,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
@@ -146,9 +145,9 @@ 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:
+1 -1
View File
@@ -39,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:
+5 -6
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0613, C0116
# type: ignore[union-attr]
# pylint: disable=C0116
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -34,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:
@@ -84,7 +83,7 @@ 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.
updater = Updater("TOKEN")
+8 -7
View File
@@ -1,14 +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
pyupgrade==2.7.4
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
+2 -1
View File
@@ -1,5 +1,6 @@
# Make sure to install those as additional_dependencies in the
# pre-commit hooks for pylint & mypy
certifi
cryptography
# only telegram.ext: # Keep this line here; used in setup(-raw).py
tornado>=5.1
APScheduler==3.6.3
+7 -1
View File
@@ -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
+6 -3
View File
@@ -53,8 +53,9 @@ def get_setup_kwargs(raw=False):
fn = os.path.join('telegram', 'version.py')
with open(fn) as fh:
code = compile(fh.read(), fn, 'exec')
exec(code)
for line in fh.readlines():
if line.startswith('__version__'):
exec(line)
with open(readme, 'r', encoding='utf-8') as fd:
@@ -84,7 +85,9 @@ def get_setup_kwargs(raw=False):
install_requires=requirements,
extras_require={
'json': 'ujson',
'socks': 'PySocks'
'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=[
+87 -78
View File
@@ -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',
)
+3 -1
View File
@@ -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}')
+2 -4
View File
@@ -46,15 +46,13 @@ class TelegramObject:
@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:
+674 -419
View File
File diff suppressed because it is too large Load Diff
+24 -23
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, List, Optional, Union, Tuple, ClassVar
from telegram import Message, TelegramObject, User, Location, ReplyMarkup, constants
from telegram.utils.types import JSONDict
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import JSONDict, ODVInput, DVInput
if TYPE_CHECKING:
from telegram import (
@@ -46,7 +47,7 @@ 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.
* 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
@@ -128,7 +129,7 @@ class CallbackQuery(TelegramObject):
show_alert: bool = False,
url: str = None,
cache_time: int = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -155,10 +156,10 @@ class CallbackQuery(TelegramObject):
def edit_message_text(
self,
text: str,
parse_mode: str = None,
disable_web_page_preview: bool = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
reply_markup: 'InlineKeyboardMarkup' = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
) -> Union[Message, bool]:
@@ -206,8 +207,8 @@ class CallbackQuery(TelegramObject):
self,
caption: str = None,
reply_markup: 'InlineKeyboardMarkup' = None,
timeout: float = None,
parse_mode: str = 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]:
@@ -253,7 +254,7 @@ class CallbackQuery(TelegramObject):
def edit_message_reply_markup(
self,
reply_markup: Optional['InlineKeyboardMarkup'] = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> Union[Message, bool]:
"""Shortcut for either::
@@ -300,7 +301,7 @@ class CallbackQuery(TelegramObject):
self,
media: 'InputMedia' = None,
reply_markup: 'InlineKeyboardMarkup' = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> Union[Message, bool]:
"""Shortcut for either::
@@ -343,7 +344,7 @@ class CallbackQuery(TelegramObject):
longitude: float = None,
location: Location = None,
reply_markup: 'InlineKeyboardMarkup' = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
horizontal_accuracy: float = None,
heading: int = None,
@@ -398,7 +399,7 @@ class CallbackQuery(TelegramObject):
def stop_message_live_location(
self,
reply_markup: 'InlineKeyboardMarkup' = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> Union[Message, bool]:
"""Shortcut for either::
@@ -441,7 +442,7 @@ class CallbackQuery(TelegramObject):
score: int,
force: bool = None,
disable_edit_message: bool = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> Union[Message, bool]:
"""Shortcut for either::
@@ -485,7 +486,7 @@ class CallbackQuery(TelegramObject):
def get_game_high_scores(
self,
user_id: Union[int, str],
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> List['GameHighScore']:
"""Shortcut for either::
@@ -521,7 +522,7 @@ class CallbackQuery(TelegramObject):
def delete_message(
self,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -542,8 +543,8 @@ class CallbackQuery(TelegramObject):
def pin_message(
self,
disable_notification: bool = None,
timeout: float = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -568,7 +569,7 @@ class CallbackQuery(TelegramObject):
def unpin_message(
self,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -594,13 +595,13 @@ class CallbackQuery(TelegramObject):
self,
chat_id: Union[int, str],
caption: str = None,
parse_mode: str = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
allow_sending_without_reply: bool = False,
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: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> 'MessageId':
"""Shortcut for::
+241 -116
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=C0103,W0622
# pylint: disable=W0622
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2021
@@ -22,16 +22,17 @@ from datetime import datetime
from typing import TYPE_CHECKING, List, Optional, ClassVar, Union, Tuple, Any
from telegram import ChatPhoto, TelegramObject, constants
from telegram.utils.types import JSONDict, FileInput
from telegram.utils.types import JSONDict, FileInput, ODVInput, DVInput
from .chatpermissions import ChatPermissions
from .chatlocation import ChatLocation
from .utils.helpers import DefaultValue, DEFAULT_NONE
from .utils.helpers import DEFAULT_NONE, DEFAULT_20
if TYPE_CHECKING:
from telegram import (
Bot,
ChatMember,
ChatInviteLink,
Message,
MessageId,
ReplyMarkup,
@@ -80,10 +81,8 @@ class Chat(TelegramObject):
:meth:`telegram.Bot.get_chat`.
description (:obj:`str`, optional): Description, for groups, supergroups and channel chats.
Returned only in :meth:`telegram.Bot.get_chat`.
invite_link (:obj:`str`, optional): Chat invite link, for groups, supergroups and channel
chats. Each administrator in a chat generates their own invite links, so the bot must
first generate the link using ``export_chat_invite_link()``. Returned only
in :meth:`telegram.Bot.get_chat`.
invite_link (:obj:`str`, optional): Primary invite link, for groups, supergroups and
channel. Returned only in :meth:`telegram.Bot.get_chat`.
pinned_message (:class:`telegram.Message`, optional): The most recent pinned message
(by sending date). Returned only in :meth:`telegram.Bot.get_chat`.
permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions,
@@ -91,6 +90,11 @@ class Chat(TelegramObject):
slow_mode_delay (:obj:`int`, optional): For supergroups, the minimum allowed delay between
consecutive messages sent by each unprivileged user.
Returned only in :meth:`telegram.Bot.get_chat`.
message_auto_delete_time (:obj:`int`, optional): The time after which all messages sent to
the chat will be automatically deleted; in seconds. Returned only in
:meth:`telegram.Bot.get_chat`.
.. versionadded:: 13.4
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
sticker_set_name (:obj:`str`, optional): For supergroups, name of group sticker set.
Returned only in :meth:`telegram.Bot.get_chat`.
@@ -114,7 +118,8 @@ class Chat(TelegramObject):
bio (:obj:`str`): Optional. Bio of the other party in a private chat. Returned only in
:meth:`telegram.Bot.get_chat`.
description (:obj:`str`): Optional. Description, for groups, supergroups and channel chats.
invite_link (:obj:`str`): Optional. Chat invite link, for supergroups and channel chats.
invite_link (:obj:`str`): Optional. Primary invite link, for groups, supergroups and
channel. Returned only in :meth:`telegram.Bot.get_chat`.
pinned_message (:class:`telegram.Message`): Optional. The most recent pinned message
(by sending date). Returned only in :meth:`telegram.Bot.get_chat`.
permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions,
@@ -122,6 +127,11 @@ class Chat(TelegramObject):
slow_mode_delay (:obj:`int`): Optional. For supergroups, the minimum allowed delay between
consecutive messages sent by each unprivileged user. Returned only in
:meth:`telegram.Bot.get_chat`.
message_auto_delete_time (:obj:`int`): Optional. The time after which all messages sent to
the chat will be automatically deleted; in seconds. Returned only in
:meth:`telegram.Bot.get_chat`.
.. versionadded:: 13.4
sticker_set_name (:obj:`str`): Optional. For supergroups, name of Group sticker set.
can_set_sticker_set (:obj:`bool`): Optional. :obj:`True`, if the bot can change group the
sticker set.
@@ -162,10 +172,11 @@ class Chat(TelegramObject):
bio: str = None,
linked_chat_id: int = None,
location: ChatLocation = None,
message_auto_delete_time: int = None,
**_kwargs: Any,
):
# Required
self.id = int(id)
self.id = int(id) # pylint: disable=C0103
self.type = type
# Optionals
self.title = title
@@ -181,6 +192,9 @@ class Chat(TelegramObject):
self.pinned_message = pinned_message
self.permissions = permissions
self.slow_mode_delay = slow_mode_delay
self.message_auto_delete_time = (
int(message_auto_delete_time) if message_auto_delete_time is not None else None
)
self.sticker_set_name = sticker_set_name
self.can_set_sticker_set = can_set_sticker_set
self.linked_chat_id = linked_chat_id
@@ -216,7 +230,7 @@ class Chat(TelegramObject):
return None
@classmethod
def de_json(cls, data: JSONDict, bot: 'Bot') -> Optional['Chat']:
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Chat']:
data = cls.parse_data(data)
if not data:
@@ -231,7 +245,7 @@ class Chat(TelegramObject):
return cls(bot=bot, **data)
def leave(self, timeout: float = None, api_kwargs: JSONDict = None) -> bool:
def leave(self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None) -> bool:
"""Shortcut for::
bot.leave_chat(update.effective_chat.id, *args, **kwargs)
@@ -249,7 +263,7 @@ class Chat(TelegramObject):
)
def get_administrators(
self, timeout: float = None, api_kwargs: JSONDict = None
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
) -> List['ChatMember']:
"""Shortcut for::
@@ -271,7 +285,9 @@ class Chat(TelegramObject):
api_kwargs=api_kwargs,
)
def get_members_count(self, timeout: float = None, api_kwargs: JSONDict = None) -> int:
def get_members_count(
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
) -> int:
"""Shortcut for::
bot.get_chat_members_count(update.effective_chat.id, *args, **kwargs)
@@ -292,7 +308,7 @@ class Chat(TelegramObject):
def get_member(
self,
user_id: Union[str, int],
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> 'ChatMember':
"""Shortcut for::
@@ -315,9 +331,10 @@ class Chat(TelegramObject):
def kick_member(
self,
user_id: Union[str, int],
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
until_date: Union[int, datetime] = None,
api_kwargs: JSONDict = None,
revoke_messages: bool = None,
) -> bool:
"""Shortcut for::
@@ -341,12 +358,13 @@ class Chat(TelegramObject):
timeout=timeout,
until_date=until_date,
api_kwargs=api_kwargs,
revoke_messages=revoke_messages,
)
def unban_member(
self,
user_id: Union[str, int],
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
only_if_banned: bool = None,
) -> bool:
@@ -379,9 +397,11 @@ class Chat(TelegramObject):
can_restrict_members: bool = None,
can_pin_messages: bool = None,
can_promote_members: bool = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
is_anonymous: bool = None,
can_manage_chat: bool = None,
can_manage_voice_chats: bool = None,
) -> bool:
"""Shortcut for::
@@ -410,6 +430,8 @@ class Chat(TelegramObject):
timeout=timeout,
api_kwargs=api_kwargs,
is_anonymous=is_anonymous,
can_manage_chat=can_manage_chat,
can_manage_voice_chats=can_manage_voice_chats,
)
def restrict_member(
@@ -417,7 +439,7 @@ class Chat(TelegramObject):
user_id: Union[str, int],
permissions: ChatPermissions,
until_date: Union[int, datetime] = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -445,7 +467,7 @@ class Chat(TelegramObject):
def set_permissions(
self,
permissions: ChatPermissions,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -470,7 +492,7 @@ class Chat(TelegramObject):
self,
user_id: Union[int, str],
custom_title: str,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -494,9 +516,9 @@ class Chat(TelegramObject):
def pin_message(
self,
message_id: Union[str, int],
disable_notification: bool = None,
timeout: float = None,
message_id: int,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -522,9 +544,9 @@ class Chat(TelegramObject):
def unpin_message(
self,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
message_id: Union[str, int] = None,
message_id: int = None,
) -> bool:
"""Shortcut for::
@@ -548,7 +570,7 @@ class Chat(TelegramObject):
def unpin_all_messages(
self,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -573,14 +595,14 @@ class Chat(TelegramObject):
def send_message(
self,
text: str,
parse_mode: str = None,
disable_web_page_preview: bool = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
) -> 'Message':
"""Shortcut for::
@@ -612,11 +634,11 @@ class Chat(TelegramObject):
media: List[
Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo']
],
disable_notification: bool = None,
reply_to_message_id: Union[int, str] = None,
timeout: float = 20,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
timeout: DVInput[float] = DEFAULT_20,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
) -> List['Message']:
"""Shortcut for::
@@ -641,7 +663,7 @@ class Chat(TelegramObject):
def send_chat_action(
self,
action: str,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -668,13 +690,13 @@ class Chat(TelegramObject):
self,
photo: Union[FileInput, 'PhotoSize'],
caption: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = 20,
parse_mode: str = None,
timeout: DVInput[float] = DEFAULT_20,
parse_mode: ODVInput[str] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
) -> 'Message':
@@ -708,14 +730,14 @@ class Chat(TelegramObject):
phone_number: str = None,
first_name: str = None,
last_name: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
contact: 'Contact' = None,
vcard: str = None,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
) -> 'Message':
"""Shortcut for::
@@ -749,14 +771,14 @@ class Chat(TelegramObject):
performer: str = None,
title: str = None,
caption: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = 20,
parse_mode: str = None,
timeout: DVInput[float] = DEFAULT_20,
parse_mode: ODVInput[str] = DEFAULT_NONE,
thumb: FileInput = None,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
) -> 'Message':
@@ -794,15 +816,15 @@ class Chat(TelegramObject):
document: Union[FileInput, 'Document'],
filename: str = None,
caption: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = 20,
parse_mode: str = None,
timeout: DVInput[float] = DEFAULT_20,
parse_mode: ODVInput[str] = DEFAULT_NONE,
thumb: FileInput = None,
api_kwargs: JSONDict = None,
disable_content_type_detection: bool = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
) -> 'Message':
"""Shortcut for::
@@ -834,13 +856,13 @@ class Chat(TelegramObject):
def send_dice(
self,
disable_notification: bool = None,
reply_to_message_id: Union[int, str] = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
emoji: str = None,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
) -> 'Message':
"""Shortcut for::
@@ -866,12 +888,12 @@ class Chat(TelegramObject):
def send_game(
self,
game_short_name: str,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'InlineKeyboardMarkup' = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
) -> 'Message':
"""Shortcut for::
@@ -912,15 +934,15 @@ class Chat(TelegramObject):
need_email: bool = None,
need_shipping_address: bool = None,
is_flexible: bool = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'InlineKeyboardMarkup' = None,
provider_data: Union[str, object] = None,
send_phone_number_to_provider: bool = None,
send_email_to_provider: bool = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
) -> 'Message':
"""Shortcut for::
@@ -965,17 +987,17 @@ class Chat(TelegramObject):
self,
latitude: float = None,
longitude: float = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
location: 'Location' = None,
live_period: int = None,
api_kwargs: JSONDict = None,
horizontal_accuracy: float = None,
heading: int = None,
proximity_alert_radius: int = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
) -> 'Message':
"""Shortcut for::
@@ -1012,13 +1034,13 @@ class Chat(TelegramObject):
height: int = None,
thumb: FileInput = None,
caption: str = None,
parse_mode: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = 20,
timeout: DVInput[float] = DEFAULT_20,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
) -> 'Message':
@@ -1054,12 +1076,12 @@ class Chat(TelegramObject):
def send_sticker(
self,
sticker: Union[FileInput, 'Sticker'],
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = 20,
timeout: DVInput[float] = DEFAULT_20,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
) -> 'Message':
"""Shortcut for::
@@ -1089,16 +1111,16 @@ class Chat(TelegramObject):
title: str = None,
address: str = None,
foursquare_id: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
venue: 'Venue' = None,
foursquare_type: str = None,
api_kwargs: JSONDict = None,
google_place_id: str = None,
google_place_type: str = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
) -> 'Message':
"""Shortcut for::
@@ -1134,17 +1156,17 @@ class Chat(TelegramObject):
video: Union[FileInput, 'Video'],
duration: int = None,
caption: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = 20,
timeout: DVInput[float] = DEFAULT_20,
width: int = None,
height: int = None,
parse_mode: str = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
supports_streaming: bool = None,
thumb: FileInput = None,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
) -> 'Message':
@@ -1183,13 +1205,13 @@ class Chat(TelegramObject):
video_note: Union[FileInput, 'VideoNote'],
duration: int = None,
length: int = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = 20,
timeout: DVInput[float] = DEFAULT_20,
thumb: FileInput = None,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
filename: str = None,
) -> 'Message':
"""Shortcut for::
@@ -1222,13 +1244,13 @@ class Chat(TelegramObject):
voice: Union[FileInput, 'Voice'],
duration: int = None,
caption: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = 20,
parse_mode: str = None,
timeout: DVInput[float] = DEFAULT_20,
parse_mode: ODVInput[str] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
) -> 'Message':
@@ -1268,16 +1290,16 @@ class Chat(TelegramObject):
allows_multiple_answers: bool = False,
correct_option_id: int = None,
is_closed: bool = None,
disable_notification: bool = None,
reply_to_message_id: Union[int, str] = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'ReplyMarkup' = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
explanation: str = None,
explanation_parse_mode: Union[str, DefaultValue, None] = DEFAULT_NONE,
explanation_parse_mode: ODVInput[str] = DEFAULT_NONE,
open_period: int = None,
close_date: Union[int, datetime] = None,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
) -> 'Message':
"""Shortcut for::
@@ -1315,15 +1337,15 @@ class Chat(TelegramObject):
def send_copy(
self,
from_chat_id: Union[str, int],
message_id: Union[str, int],
message_id: int,
caption: str = None,
parse_mode: str = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
allow_sending_without_reply: bool = False,
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: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> 'MessageId':
"""Shortcut for::
@@ -1354,15 +1376,15 @@ class Chat(TelegramObject):
def copy_message(
self,
chat_id: Union[int, str],
message_id: Union[str, int],
message_id: int,
caption: str = None,
parse_mode: str = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
allow_sending_without_reply: bool = False,
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: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> 'MessageId':
"""Shortcut for::
@@ -1389,3 +1411,106 @@ class Chat(TelegramObject):
timeout=timeout,
api_kwargs=api_kwargs,
)
def export_invite_link(
self,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> str:
"""Shortcut for::
bot.export_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.export_chat_invite_link`.
.. versionadded:: 13.4
Returns:
:obj:`str`: New invite link on success.
"""
return self.bot.export_chat_invite_link(
chat_id=self.id, timeout=timeout, api_kwargs=api_kwargs
)
def create_invite_link(
self,
expire_date: Union[int, datetime] = None,
member_limit: int = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> 'ChatInviteLink':
"""Shortcut for::
bot.create_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.create_chat_invite_link`.
.. versionadded:: 13.4
Returns:
:class:`telegram.ChatInviteLink`
"""
return self.bot.create_chat_invite_link(
chat_id=self.id,
expire_date=expire_date,
member_limit=member_limit,
timeout=timeout,
api_kwargs=api_kwargs,
)
def edit_invite_link(
self,
invite_link: str,
expire_date: Union[int, datetime] = None,
member_limit: int = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> 'ChatInviteLink':
"""Shortcut for::
bot.edit_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.edit_chat_invite_link`.
.. versionadded:: 13.4
Returns:
:class:`telegram.ChatInviteLink`
"""
return self.bot.edit_chat_invite_link(
chat_id=self.id,
invite_link=invite_link,
expire_date=expire_date,
member_limit=member_limit,
timeout=timeout,
api_kwargs=api_kwargs,
)
def revoke_invite_link(
self,
invite_link: str,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> 'ChatInviteLink':
"""Shortcut for::
bot.revoke_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.revoke_chat_invite_link`.
.. versionadded:: 13.4
Returns:
:class:`telegram.ChatInviteLink`
"""
return self.bot.revoke_chat_invite_link(
chat_id=self.id, invite_link=invite_link, timeout=timeout, api_kwargs=api_kwargs
)
+102
View File
@@ -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
+27
View File
@@ -46,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
@@ -87,6 +99,17 @@ class ChatMember(TelegramObject):
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.
@@ -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)
+115
View File
@@ -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
+1 -1
View File
@@ -37,7 +37,7 @@ class ChosenInlineResult(TelegramObject):
considered equal, if their :attr:`result_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.
* It is necessary to enable inline feedback via `@Botfather <https://t.me/BotFather>`_ in
order to receive these objects in updates.
+13
View File
@@ -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]
@@ -88,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:
@@ -136,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
@@ -182,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'
+12 -2
View File
@@ -45,13 +45,17 @@ class Dice(TelegramObject):
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 and darts, 1-5 for basketball and
football/soccer ball, 1-64 for slot machine.
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:
@@ -76,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`"""
+2
View File
@@ -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',
)
+4 -4
View File
@@ -291,7 +291,7 @@ class BasePersistence(ABC):
@abstractmethod
def get_user_data(self) -> DefaultDict[int, Dict[object, object]]:
""" "Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
"""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)``.
@@ -301,7 +301,7 @@ class BasePersistence(ABC):
@abstractmethod
def get_chat_data(self) -> DefaultDict[int, Dict[object, object]]:
""" "Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
"""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)``.
@@ -311,7 +311,7 @@ class BasePersistence(ABC):
@abstractmethod
def get_bot_data(self) -> Dict[object, object]:
""" "Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
"""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`.
@@ -321,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`
+3 -3
View File
@@ -118,7 +118,7 @@ class CallbackContext:
@bot_data.setter
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
@@ -128,7 +128,7 @@ class CallbackContext:
@chat_data.setter
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
@@ -138,7 +138,7 @@ class CallbackContext:
@user_data.setter
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
+146
View File
@@ -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
+42 -5
View File
@@ -16,13 +16,14 @@
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
# pylint: disable=R0201, E0401
# pylint: disable=R0201
"""This module contains the class Defaults, which allows to pass default values to Updater."""
from typing import 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:
@@ -47,6 +48,9 @@ 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`.
@@ -54,6 +58,8 @@ class Defaults:
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
@@ -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,6 +101,26 @@ 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
@@ -106,6 +132,17 @@ class Defaults:
"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."
)
@property
def disable_notification(self) -> Optional[bool]:
return self._disable_notification
@@ -140,7 +177,7 @@ class Defaults:
)
@property
def timeout(self) -> Union[float, DefaultValue]:
def timeout(self) -> ODVInput[float]:
return self._timeout
@timeout.setter
+2 -2
View File
@@ -80,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:
@@ -619,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
+104 -31
View File
@@ -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]
@@ -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):
@@ -1413,7 +1472,8 @@ officedocument.wordprocessingml.document")``.
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`
@@ -1422,8 +1482,8 @@ officedocument.wordprocessingml.document")``.
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.
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`.
@@ -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)
@@ -1511,7 +1571,8 @@ officedocument.wordprocessingml.document")``.
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`
@@ -1520,8 +1581,8 @@ officedocument.wordprocessingml.document")``.
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.
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`.
@@ -1554,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)
@@ -1576,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)
@@ -1610,7 +1671,7 @@ officedocument.wordprocessingml.document")``.
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`
@@ -1619,8 +1680,8 @@ officedocument.wordprocessingml.document")``.
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.
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`.
@@ -1636,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)
@@ -1657,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)
@@ -1677,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`,
@@ -1700,7 +1767,7 @@ officedocument.wordprocessingml.document")``.
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.
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`
@@ -1711,7 +1778,7 @@ officedocument.wordprocessingml.document")``.
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.
@@ -1735,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)
@@ -1756,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)
@@ -1827,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
@@ -1859,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):
@@ -1892,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):
-1
View File
@@ -16,7 +16,6 @@
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
# pylint: disable=E0401
"""This module contains the classes JobQueue and Job."""
import datetime
+22
View File
@@ -24,9 +24,11 @@ import functools
import queue as q
import threading
import time
import warnings
from typing import TYPE_CHECKING, Callable, List, NoReturn
from telegram.ext.utils.promise import Promise
from telegram.utils.deprecate import TelegramDeprecationWarning
if TYPE_CHECKING:
from telegram import Bot
@@ -44,6 +46,10 @@ class DelayQueue(threading.Thread):
Processes callbacks from queue with specified throughput limits. Creates a separate thread to
process callbacks with delays.
.. 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``
implicitly if not provided.
@@ -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
@@ -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,
+112 -61
View File
@@ -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:
+5 -5
View File
@@ -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 asyncio
import logging
@@ -95,7 +95,7 @@ class WebhookServer:
not force_event_loop
and os.name == 'nt'
and sys.version_info >= (3, 8)
and isinstance(loop, asyncio.ProactorEventLoop)
and isinstance(loop, asyncio.ProactorEventLoop) # type: ignore[attr-defined]
):
raise TypeError(
'`ProactorEventLoop` is incompatible with '
@@ -123,7 +123,7 @@ class WebhookServer:
and (
isinstance(
asyncio.get_event_loop_policy(),
asyncio.WindowsProactorEventLoopPolicy, # pylint: disable=E1101
asyncio.WindowsProactorEventLoopPolicy, # type: ignore # pylint: disable
)
)
): # pylint: disable=E1101
@@ -140,7 +140,7 @@ 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)
tornado.web.Application.__init__(self, handlers) # type: ignore
def log_request(self, handler: tornado.web.RequestHandler) -> None:
pass
@@ -149,7 +149,7 @@ class WebhookAppClass(tornado.web.Application):
# WebhookHandler, process webhook calls
# pylint: disable=W0223
class WebhookHandler(tornado.web.RequestHandler):
SUPPORTED_METHODS = ["POST"]
SUPPORTED_METHODS = ["POST"] # type: ignore
def __init__(
self,
+5 -2
View File
@@ -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
@@ -104,7 +105,9 @@ class Animation(TelegramObject):
return cls(bot=bot, **data)
def get_file(self, timeout: float = 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`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
+5 -2
View File
@@ -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
@@ -108,7 +109,9 @@ class Audio(TelegramObject):
return cls(bot=bot, **data)
def get_file(self, timeout: float = 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`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
+8 -3
View File
@@ -20,7 +20,8 @@
from typing import TYPE_CHECKING, Any
from telegram import 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
@@ -85,7 +86,9 @@ class ChatPhoto(TelegramObject):
self.big_file_unique_id,
)
def get_small_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> '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
@@ -102,7 +105,9 @@ class ChatPhoto(TelegramObject):
file_id=self.small_file_id, timeout=timeout, api_kwargs=api_kwargs
)
def get_big_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> '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
+5 -2
View File
@@ -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
@@ -95,7 +96,9 @@ class Document(TelegramObject):
return cls(bot=bot, **data)
def get_file(self, timeout: float = 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`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
+7 -7
View File
@@ -30,8 +30,8 @@ from telegram import (
Video,
MessageEntity,
)
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue, parse_file_input
from telegram.utils.types import FileInput, JSONDict
from telegram.utils.helpers import DEFAULT_NONE, parse_file_input
from telegram.utils.types import FileInput, JSONDict, ODVInput
class InputMedia(TelegramObject):
@@ -117,7 +117,7 @@ class InputMediaAnimation(InputMedia):
media: Union[FileInput, Animation],
thumb: FileInput = None,
caption: str = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
width: int = None,
height: int = None,
duration: int = None,
@@ -188,7 +188,7 @@ class InputMediaPhoto(InputMedia):
self,
media: Union[FileInput, PhotoSize],
caption: str = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
filename: str = None,
):
@@ -272,7 +272,7 @@ class InputMediaVideo(InputMedia):
height: int = None,
duration: int = None,
supports_streaming: bool = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
thumb: FileInput = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
filename: str = None,
@@ -368,7 +368,7 @@ class InputMediaAudio(InputMedia):
media: Union[FileInput, Audio],
thumb: FileInput = None,
caption: str = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
duration: int = None,
performer: str = None,
title: str = None,
@@ -456,7 +456,7 @@ class InputMediaDocument(InputMedia):
media: Union[FileInput, Document],
thumb: FileInput = None,
caption: str = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_content_type_detection: bool = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
filename: str = None,
+5 -2
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any
from telegram import 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
@@ -78,7 +79,9 @@ class PhotoSize(TelegramObject):
self._id_attrs = (self.file_unique_id,)
def get_file(self, timeout: float = 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`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
+5 -2
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, List, Optional, ClassVar
from telegram import PhotoSize, TelegramObject, constants
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
@@ -115,7 +116,9 @@ class Sticker(TelegramObject):
return cls(bot=bot, **data)
def get_file(self, timeout: float = 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`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
+5 -2
View File
@@ -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
@@ -105,7 +106,9 @@ class Video(TelegramObject):
return cls(bot=bot, **data)
def get_file(self, timeout: float = 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`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
+5 -2
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Optional, Any
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
@@ -94,7 +95,9 @@ class VideoNote(TelegramObject):
return cls(bot=bot, **data)
def get_file(self, timeout: float = 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`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
+5 -2
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any
from telegram import 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
@@ -78,7 +79,9 @@ class Voice(TelegramObject):
self._id_attrs = (self.file_unique_id,)
def get_file(self, timeout: float = 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`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
+8 -7
View File
@@ -19,10 +19,11 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram InlineQuery."""
from typing import TYPE_CHECKING, Any, Optional, List, Union, Callable, ClassVar
from typing import TYPE_CHECKING, Any, Optional, Union, Callable, ClassVar, Sequence
from telegram import Location, TelegramObject, User, constants
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, InlineQueryResult
@@ -37,7 +38,7 @@ class InlineQuery(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.
Args:
id (:obj:`str`): Unique identifier for this query.
@@ -96,14 +97,14 @@ class InlineQuery(TelegramObject):
def answer(
self,
results: Union[
List['InlineQueryResult'], Callable[[int], Optional[List['InlineQueryResult']]]
Sequence['InlineQueryResult'], Callable[[int], Optional[Sequence['InlineQueryResult']]]
],
cache_time: int = 300,
is_personal: bool = None,
next_offset: str = None,
switch_pm_text: str = None,
switch_pm_parameter: str = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
current_offset: str = None,
api_kwargs: JSONDict = None,
auto_pagination: bool = False,
@@ -120,11 +121,11 @@ class InlineQuery(TelegramObject):
Args:
auto_pagination (:obj:`bool`, optional): If set to :obj:`True`, :attr:`offset` will be
passed as :attr:`current_offset` to :meth:telegram.Bot.answer_inline_query`.
passed as :attr:`current_offset` to :meth:`telegram.Bot.answer_inline_query`.
Defaults to :obj:`False`.
Raises:
TypeError: If both :attr:`current_offset` and `auto_pagination` are supplied.
TypeError: If both :attr:`current_offset` and :attr:`auto_pagination` are supplied.
"""
if current_offset and auto_pagination:
# We raise TypeError instead of ValueError for backwards compatibility with versions
+4 -8
View File
@@ -31,6 +31,10 @@ class InlineQueryResult(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`id` is equal.
Note:
All URLs passed in inline query results will be available to end users and therefore must
be assumed to be public.
Args:
type (:obj:`str`): Type of the result.
id (:obj:`str`): Unique identifier for this result, 1-64 Bytes.
@@ -49,14 +53,6 @@ class InlineQueryResult(TelegramObject):
self._id_attrs = (self.id,)
@property
def _has_parse_mode(self) -> bool:
return hasattr(self, 'parse_mode')
@property
def _has_input_message_content(self) -> bool:
return hasattr(self, 'input_message_content')
def to_dict(self) -> JSONDict:
data = super().to_dict()
+3 -2
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -83,7 +84,7 @@ class InlineQueryResultAudio(InlineQueryResult):
caption: str = None,
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -74,7 +75,7 @@ class InlineQueryResultCachedAudio(InlineQueryResult):
caption: str = None,
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
@@ -22,7 +22,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -83,7 +84,7 @@ class InlineQueryResultCachedDocument(InlineQueryResult):
caption: str = None,
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -80,7 +81,7 @@ class InlineQueryResultCachedGif(InlineQueryResult):
caption: str = None,
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -80,7 +81,7 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
caption: str = None,
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
@@ -22,7 +22,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -84,7 +85,7 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
caption: str = None,
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -83,7 +84,7 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
caption: str = None,
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -77,7 +78,7 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
caption: str = None,
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
+3 -2
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -97,7 +98,7 @@ class InlineQueryResultDocument(InlineQueryResult):
thumb_url: str = None,
thumb_width: int = None,
thumb_height: int = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
+3 -2
View File
@@ -22,7 +22,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -97,7 +98,7 @@ class InlineQueryResultGif(InlineQueryResult):
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
gif_duration: int = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
thumb_mime_type: str = None,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
+3 -2
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -96,7 +97,7 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
mpeg4_duration: int = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
thumb_mime_type: str = None,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
+3 -2
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -93,7 +94,7 @@ class InlineQueryResultPhoto(InlineQueryResult):
caption: str = None,
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
+3 -2
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -105,7 +106,7 @@ class InlineQueryResultVideo(InlineQueryResult):
description: str = None,
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
+3 -2
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Union, Tuple, List
from telegram import InlineQueryResult, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
if TYPE_CHECKING:
from telegram import InputMessageContent, ReplyMarkup
@@ -81,7 +82,7 @@ class InlineQueryResultVoice(InlineQueryResult):
caption: str = None,
reply_markup: 'ReplyMarkup' = None,
input_message_content: 'InputMessageContent' = None,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
-8
View File
@@ -29,11 +29,3 @@ class InputMessageContent(TelegramObject):
:class:`telegram.InputVenueMessageContent` for more details.
"""
@property
def _has_parse_mode(self) -> bool:
return hasattr(self, 'parse_mode')
@property
def _has_disable_web_page_preview(self) -> bool:
return hasattr(self, 'disable_web_page_preview')
+4 -4
View File
@@ -21,8 +21,8 @@
from typing import Any, Union, Tuple, List
from telegram import InputMessageContent, MessageEntity
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
from telegram.utils.types import JSONDict
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import JSONDict, ODVInput
class InputTextMessageContent(InputMessageContent):
@@ -62,8 +62,8 @@ class InputTextMessageContent(InputMessageContent):
def __init__(
self,
message_text: str,
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
disable_web_page_preview: Union[bool, DefaultValue] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
**_kwargs: Any,
):
+2 -2
View File
@@ -20,7 +20,7 @@
from typing import Any
from telegram import TelegramObject
from telegram import TelegramObject, KeyboardButtonPollType
class KeyboardButton(TelegramObject):
@@ -63,7 +63,7 @@ class KeyboardButton(TelegramObject):
text: str,
request_contact: bool = None,
request_location: bool = None,
request_poll: bool = None,
request_poll: KeyboardButtonPollType = None,
**_kwargs: Any,
):
# Required
+182 -129
View File
@@ -47,17 +47,21 @@ from telegram import (
Video,
VideoNote,
Voice,
VoiceChatStarted,
VoiceChatEnded,
VoiceChatParticipantsInvited,
ProximityAlertTriggered,
ReplyMarkup,
MessageAutoDeleteTimerChanged,
)
from telegram.utils.helpers import (
escape_markdown,
from_timestamp,
to_timestamp,
DEFAULT_NONE,
DefaultValue,
DEFAULT_20,
)
from telegram.utils.types import JSONDict, FileInput
from telegram.utils.types import JSONDict, FileInput, ODVInput, DVInput
if TYPE_CHECKING:
from telegram import (
@@ -83,7 +87,7 @@ class Message(TelegramObject):
considered equal, if their :attr:`message_id` and :attr:`chat` are equal.
Note:
In Python `from` is a reserved word, use `from_user` instead.
In Python ``from`` is a reserved word, use ``from_user`` instead.
Args:
message_id (:obj:`int`): Unique message identifier inside this chat.
@@ -165,6 +169,10 @@ class Message(TelegramObject):
created. This field can't be received in a message coming through updates, because bot
can't be a member of a channel when it is created. It can only be found in
:attr:`reply_to_message` if someone replies to a very first message in a channel.
message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`, \
optional): Service message: auto-delete timer settings changed in the chat.
.. versionadded:: 13.4
migrate_to_chat_id (:obj:`int`, optional): The group has been migrated to a supergroup with
the specified identifier. This number may be greater than 32 bits and some programming
languages may have difficulty/silent defects in interpreting it. But it is smaller than
@@ -196,6 +204,18 @@ class Message(TelegramObject):
proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`, optional): Service
message. A user in the chat triggered another user's proximity alert while sharing
Live Location.
voice_chat_started (:class:`telegram.VoiceChatStarted`, optional): Service message: voice
chat started.
.. versionadded:: 13.4
voice_chat_ended (:class:`telegram.VoiceChatEnded`, optional): Service message: voice chat
ended.
.. versionadded:: 13.4
voice_chat_participants_invited (:class:`telegram.VoiceChatParticipantsInvited` optional):
Service message: new participants invited to a voice chat.
.. versionadded:: 13.4
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message. ``login_url`` buttons are represented as ordinary url buttons.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
@@ -257,6 +277,10 @@ class Message(TelegramObject):
group_chat_created (:obj:`bool`): Optional. The group has been created.
supergroup_chat_created (:obj:`bool`): Optional. The supergroup has been created.
channel_chat_created (:obj:`bool`): Optional. The channel has been created.
message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`):
Optional. Service message: auto-delete timer settings changed in the chat.
.. versionadded:: 13.4
migrate_to_chat_id (:obj:`int`): Optional. The group has been migrated to a supergroup with
the specified identifier.
migrate_from_chat_id (:obj:`int`): Optional. The supergroup has been migrated from a group
@@ -281,6 +305,18 @@ class Message(TelegramObject):
proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`): Optional. Service
message. A user in the chat triggered another user's proximity alert while sharing
Live Location.
voice_chat_started (:class:`telegram.VoiceChatStarted`): Optional. Service message: voice
chat started
.. versionadded:: 13.4
voice_chat_ended (:class:`telegram.VoiceChatEnded`): Optional. Service message: voice chat
ended.
.. versionadded:: 13.4
voice_chat_participants_invited (:class:`telegram.VoiceChatParticipantsInvited`): Optional.
Service message: new participants invited to a voice chat.
.. versionadded:: 13.4
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
@@ -316,6 +352,7 @@ class Message(TelegramObject):
'group_chat_created',
'supergroup_chat_created',
'channel_chat_created',
'message_auto_delete_timer_changed',
'migrate_to_chat_id',
'migrate_from_chat_id',
'pinned_message',
@@ -323,6 +360,9 @@ class Message(TelegramObject):
'dice',
'passport_data',
'proximity_alert_triggered',
'voice_chat_started',
'voice_chat_ended',
'voice_chat_participants_invited',
] + ATTACHMENT_TYPES
def __init__(
@@ -379,6 +419,10 @@ class Message(TelegramObject):
via_bot: User = None,
proximity_alert_triggered: ProximityAlertTriggered = None,
sender_chat: Chat = None,
voice_chat_started: VoiceChatStarted = None,
voice_chat_ended: VoiceChatEnded = None,
voice_chat_participants_invited: VoiceChatParticipantsInvited = None,
message_auto_delete_timer_changed: MessageAutoDeleteTimerChanged = None,
**_kwargs: Any,
):
# Required
@@ -418,6 +462,7 @@ class Message(TelegramObject):
self.migrate_to_chat_id = migrate_to_chat_id
self.migrate_from_chat_id = migrate_from_chat_id
self.channel_chat_created = bool(channel_chat_created)
self.message_auto_delete_timer_changed = message_auto_delete_timer_changed
self.pinned_message = pinned_message
self.forward_from_message_id = forward_from_message_id
self.invoice = invoice
@@ -433,6 +478,9 @@ class Message(TelegramObject):
self.dice = dice
self.via_bot = via_bot
self.proximity_alert_triggered = proximity_alert_triggered
self.voice_chat_started = voice_chat_started
self.voice_chat_ended = voice_chat_ended
self.voice_chat_participants_invited = voice_chat_participants_invited
self.reply_markup = reply_markup
self.bot = bot
@@ -489,6 +537,9 @@ class Message(TelegramObject):
data['new_chat_members'] = User.de_list(data.get('new_chat_members'), bot)
data['left_chat_member'] = User.de_json(data.get('left_chat_member'), bot)
data['new_chat_photo'] = PhotoSize.de_list(data.get('new_chat_photo'), bot)
data['message_auto_delete_timer_changed'] = MessageAutoDeleteTimerChanged.de_json(
data.get('message_auto_delete_timer_changed'), bot
)
data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot)
data['invoice'] = Invoice.de_json(data.get('invoice'), bot)
data['successful_payment'] = SuccessfulPayment.de_json(data.get('successful_payment'), bot)
@@ -500,7 +551,11 @@ class Message(TelegramObject):
data.get('proximity_alert_triggered'), bot
)
data['reply_markup'] = InlineKeyboardMarkup.de_json(data.get('reply_markup'), bot)
data['voice_chat_started'] = VoiceChatStarted.de_json(data.get('voice_chat_started'), bot)
data['voice_chat_ended'] = VoiceChatEnded.de_json(data.get('voice_chat_ended'), bot)
data['voice_chat_participants_invited'] = VoiceChatParticipantsInvited.de_json(
data.get('voice_chat_participants_invited'), bot
)
return cls(bot=bot, **data)
@property
@@ -581,9 +636,7 @@ class Message(TelegramObject):
return data
def _quote(
self, quote: Optional[bool], reply_to_message_id: Optional[Union[int, str]]
) -> Optional[Union[int, str]]:
def _quote(self, quote: Optional[bool], reply_to_message_id: Optional[int]) -> Optional[int]:
"""Modify kwargs for replying with or without quoting."""
if reply_to_message_id is not None:
return reply_to_message_id
@@ -605,14 +658,14 @@ class Message(TelegramObject):
def reply_text(
self,
text: str,
parse_mode: str = None,
disable_web_page_preview: bool = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
quote: bool = None,
) -> 'Message':
@@ -650,13 +703,13 @@ class Message(TelegramObject):
def reply_markdown(
self,
text: str,
disable_web_page_preview: bool = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
quote: bool = None,
) -> 'Message':
@@ -704,13 +757,13 @@ class Message(TelegramObject):
def reply_markdown_v2(
self,
text: str,
disable_web_page_preview: bool = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
quote: bool = None,
) -> 'Message':
@@ -754,13 +807,13 @@ class Message(TelegramObject):
def reply_html(
self,
text: str,
disable_web_page_preview: bool = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
quote: bool = None,
) -> 'Message':
@@ -806,11 +859,11 @@ class Message(TelegramObject):
media: List[
Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo']
],
disable_notification: bool = None,
reply_to_message_id: Union[int, str] = None,
timeout: float = 20,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
timeout: DVInput[float] = DEFAULT_20,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
) -> List['Message']:
"""Shortcut for::
@@ -846,13 +899,13 @@ class Message(TelegramObject):
self,
photo: Union[FileInput, 'PhotoSize'],
caption: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = 20,
parse_mode: str = None,
timeout: DVInput[float] = DEFAULT_20,
parse_mode: ODVInput[str] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
quote: bool = None,
@@ -896,14 +949,14 @@ class Message(TelegramObject):
performer: str = None,
title: str = None,
caption: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = 20,
parse_mode: str = None,
timeout: DVInput[float] = DEFAULT_20,
parse_mode: ODVInput[str] = DEFAULT_NONE,
thumb: FileInput = None,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
quote: bool = None,
@@ -949,15 +1002,15 @@ class Message(TelegramObject):
document: Union[FileInput, 'Document'],
filename: str = None,
caption: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = 20,
parse_mode: str = None,
timeout: DVInput[float] = DEFAULT_20,
parse_mode: ODVInput[str] = DEFAULT_NONE,
thumb: FileInput = None,
api_kwargs: JSONDict = None,
disable_content_type_detection: bool = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
quote: bool = None,
) -> 'Message':
@@ -1003,13 +1056,13 @@ class Message(TelegramObject):
height: int = None,
thumb: FileInput = None,
caption: str = None,
parse_mode: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = 20,
timeout: DVInput[float] = DEFAULT_20,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
quote: bool = None,
@@ -1053,12 +1106,12 @@ class Message(TelegramObject):
def reply_sticker(
self,
sticker: Union[FileInput, 'Sticker'],
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = 20,
timeout: DVInput[float] = DEFAULT_20,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
) -> 'Message':
"""Shortcut for::
@@ -1094,17 +1147,17 @@ class Message(TelegramObject):
video: Union[FileInput, 'Video'],
duration: int = None,
caption: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = 20,
timeout: DVInput[float] = DEFAULT_20,
width: int = None,
height: int = None,
parse_mode: str = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
supports_streaming: bool = None,
thumb: FileInput = None,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
quote: bool = None,
@@ -1151,13 +1204,13 @@ class Message(TelegramObject):
video_note: Union[FileInput, 'VideoNote'],
duration: int = None,
length: int = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = 20,
timeout: DVInput[float] = DEFAULT_20,
thumb: FileInput = None,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
filename: str = None,
quote: bool = None,
) -> 'Message':
@@ -1198,13 +1251,13 @@ class Message(TelegramObject):
voice: Union[FileInput, 'Voice'],
duration: int = None,
caption: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = 20,
parse_mode: str = None,
timeout: DVInput[float] = DEFAULT_20,
parse_mode: ODVInput[str] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
quote: bool = None,
@@ -1246,17 +1299,17 @@ class Message(TelegramObject):
self,
latitude: float = None,
longitude: float = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
location: Location = None,
live_period: int = None,
api_kwargs: JSONDict = None,
horizontal_accuracy: float = None,
heading: int = None,
proximity_alert_radius: int = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
) -> 'Message':
"""Shortcut for::
@@ -1300,16 +1353,16 @@ class Message(TelegramObject):
title: str = None,
address: str = None,
foursquare_id: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
venue: Venue = None,
foursquare_type: str = None,
api_kwargs: JSONDict = None,
google_place_id: str = None,
google_place_type: str = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
) -> 'Message':
"""Shortcut for::
@@ -1353,14 +1406,14 @@ class Message(TelegramObject):
phone_number: str = None,
first_name: str = None,
last_name: str = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
contact: Contact = None,
vcard: str = None,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
) -> 'Message':
"""Shortcut for::
@@ -1404,16 +1457,16 @@ class Message(TelegramObject):
allows_multiple_answers: bool = False,
correct_option_id: int = None,
is_closed: bool = None,
disable_notification: bool = None,
reply_to_message_id: Union[int, str] = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
explanation: str = None,
explanation_parse_mode: Union[str, DefaultValue, None] = DEFAULT_NONE,
explanation_parse_mode: ODVInput[str] = DEFAULT_NONE,
open_period: int = None,
close_date: Union[int, datetime.datetime] = None,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
quote: bool = None,
) -> 'Message':
@@ -1458,13 +1511,13 @@ class Message(TelegramObject):
def reply_dice(
self,
disable_notification: bool = None,
reply_to_message_id: Union[int, str] = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: ReplyMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
emoji: str = None,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
) -> 'Message':
"""Shortcut for::
@@ -1498,7 +1551,7 @@ class Message(TelegramObject):
def reply_chat_action(
self,
action: str,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -1523,12 +1576,12 @@ class Message(TelegramObject):
def reply_game(
self,
game_short_name: str,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'InlineKeyboardMarkup' = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
) -> 'Message':
"""Shortcut for::
@@ -1579,15 +1632,15 @@ class Message(TelegramObject):
need_email: bool = None,
need_shipping_address: bool = None,
is_flexible: bool = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int = None,
reply_markup: 'InlineKeyboardMarkup' = None,
provider_data: Union[str, object] = None,
send_phone_number_to_provider: bool = None,
send_email_to_provider: bool = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
allow_sending_without_reply: bool = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
) -> 'Message':
"""Shortcut for::
@@ -1641,8 +1694,8 @@ class Message(TelegramObject):
def forward(
self,
chat_id: Union[int, str],
disable_notification: bool = False,
timeout: float = None,
disable_notification: DVInput[bool] = DEFAULT_NONE,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> 'Message':
"""Shortcut for::
@@ -1672,13 +1725,13 @@ class Message(TelegramObject):
self,
chat_id: Union[int, str],
caption: str = None,
parse_mode: str = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
allow_sending_without_reply: bool = False,
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: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> 'MessageId':
"""Shortcut for::
@@ -1713,15 +1766,15 @@ class Message(TelegramObject):
def reply_copy(
self,
from_chat_id: Union[str, int],
message_id: Union[str, int],
message_id: int,
caption: str = None,
parse_mode: str = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None,
disable_notification: bool = False,
reply_to_message_id: Union[int, str] = None,
allow_sending_without_reply: bool = False,
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: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
quote: bool = None,
) -> 'MessageId':
@@ -1766,10 +1819,10 @@ class Message(TelegramObject):
def edit_text(
self,
text: str,
parse_mode: str = None,
disable_web_page_preview: bool = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
reply_markup: InlineKeyboardMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
) -> Union['Message', bool]:
@@ -1809,8 +1862,8 @@ class Message(TelegramObject):
self,
caption: str = None,
reply_markup: InlineKeyboardMarkup = None,
timeout: float = None,
parse_mode: str = 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]:
@@ -1850,7 +1903,7 @@ class Message(TelegramObject):
self,
media: 'InputMedia' = None,
reply_markup: InlineKeyboardMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> Union['Message', bool]:
"""Shortcut for::
@@ -1886,7 +1939,7 @@ class Message(TelegramObject):
def edit_reply_markup(
self,
reply_markup: Optional['InlineKeyboardMarkup'] = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> Union['Message', bool]:
"""Shortcut for::
@@ -1923,7 +1976,7 @@ class Message(TelegramObject):
longitude: float = None,
location: Location = None,
reply_markup: InlineKeyboardMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
horizontal_accuracy: float = None,
heading: int = None,
@@ -1966,7 +2019,7 @@ class Message(TelegramObject):
def stop_live_location(
self,
reply_markup: InlineKeyboardMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> Union['Message', bool]:
"""Shortcut for::
@@ -2003,7 +2056,7 @@ class Message(TelegramObject):
score: int,
force: bool = None,
disable_edit_message: bool = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> Union['Message', bool]:
"""Shortcut for::
@@ -2039,7 +2092,7 @@ class Message(TelegramObject):
def get_game_high_scores(
self,
user_id: Union[int, str],
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> List['GameHighScore']:
"""Shortcut for::
@@ -2071,7 +2124,7 @@ class Message(TelegramObject):
def delete(
self,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -2097,7 +2150,7 @@ class Message(TelegramObject):
def stop_poll(
self,
reply_markup: InlineKeyboardMarkup = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> Poll:
"""Shortcut for::
@@ -2124,8 +2177,8 @@ class Message(TelegramObject):
def pin(
self,
disable_notification: bool = None,
timeout: float = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
@@ -2151,7 +2204,7 @@ class Message(TelegramObject):
def unpin(
self,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
+53
View File
@@ -0,0 +1,53 @@
#!/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 change in the Telegram message auto
deletion."""
from typing import Any
from telegram import TelegramObject
class MessageAutoDeleteTimerChanged(TelegramObject):
"""This object represents a service message about a change in auto-delete timer settings.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`message_auto_delete_time` is equal.
.. versionadded:: 13.4
Args:
message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the
chat.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the
chat.
"""
def __init__(
self,
message_auto_delete_time: int,
**_kwargs: Any,
):
self.message_auto_delete_time = int(message_auto_delete_time)
self._id_attrs = (self.message_auto_delete_time,)
+26 -7
View File
@@ -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=C0114, E0401, W0622
# pylint: disable=C0114, W0622
try:
import ujson as json
except ImportError:
@@ -25,12 +25,21 @@ except ImportError:
from base64 import b64decode
from typing import TYPE_CHECKING, Any, List, Optional, Tuple, Union, no_type_check
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric.padding import MGF1, OAEP
from cryptography.hazmat.primitives.ciphers import Cipher
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.primitives.ciphers.modes import CBC
from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512, Hash
try:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric.padding import MGF1, OAEP
from cryptography.hazmat.primitives.ciphers import Cipher
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.primitives.ciphers.modes import CBC
from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512, Hash
CRYPTO_INSTALLED = True
except ImportError:
default_backend = None
MGF1, OAEP, Cipher, AES, CBC = (None, None, None, None, None) # type: ignore[misc]
SHA1, SHA256, SHA512, Hash = (None, None, None, None) # type: ignore[misc]
CRYPTO_INSTALLED = False
from telegram import TelegramError, TelegramObject
from telegram.utils.types import JSONDict
@@ -74,6 +83,11 @@ def decrypt(secret, hash, data):
:obj:`bytes`: The decrypted data as bytes.
"""
if not CRYPTO_INSTALLED:
raise RuntimeError(
'To use Telegram Passports, PTB must be installed via `pip install '
'python-telegram-bot[passport]`.'
)
# Make a SHA512 hash of secret + update
digest = Hash(SHA512(), backend=default_backend())
digest.update(secret + hash)
@@ -153,6 +167,11 @@ class EncryptedCredentials(TelegramObject):
private/public key but can also suggest malformed/tampered data.
"""
if self._decrypted_secret is None:
if not CRYPTO_INSTALLED:
raise RuntimeError(
'To use Telegram Passports, PTB must be installed via `pip install '
'python-telegram-bot[passport]`.'
)
# Try decrypting according to step 1 at
# https://core.telegram.org/passport#decrypting-data
# We make sure to base64 decode the secret first.
+5 -2
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, List, Optional
from telegram import 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, FileCredentials
@@ -103,7 +104,9 @@ class PassportFile(TelegramObject):
for i, passport_file in enumerate(data)
]
def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File':
def get_file(
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
) -> 'File':
"""
Wrapper over :attr:`telegram.Bot.get_file`. Will automatically assign the correct
credentials to the returned :class:`telegram.File` if originating from
+4 -3
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Optional
from telegram import OrderInfo, TelegramObject, User
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
@@ -34,7 +35,7 @@ class PreCheckoutQuery(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.
Args:
id (:obj:`str`): Unique query identifier.
@@ -106,7 +107,7 @@ class PreCheckoutQuery(TelegramObject):
self,
ok: bool,
error_message: str = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
+4 -3
View File
@@ -21,7 +21,8 @@
from typing import TYPE_CHECKING, Any, Optional, List
from telegram import ShippingAddress, TelegramObject, User, ShippingOption
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
@@ -34,7 +35,7 @@ class ShippingQuery(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.
Args:
id (:obj:`str`): Unique query identifier.
@@ -88,7 +89,7 @@ class ShippingQuery(TelegramObject):
ok: bool,
shipping_options: List[ShippingOption] = None,
error_message: str = None,
timeout: float = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::

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