Compare commits

...

49 Commits

Author SHA1 Message Date
Hinrich Mahler df07148e2d Bump version to v20.0a2 2022-06-27 19:19:54 +02:00
Bibo-Joshi 2d2cede442 Documentation Improvements (#3103, #3121, #3098)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: David <dsb321mp@gmail.com>
Co-authored-by: Harshil Mehta <37377066+harshil21@users.noreply.github.com>
Co-authored-by: poolitzer <github@poolitzer.eu>
Co-authored-by: Alex <53974096+ExalFabu@users.noreply.github.com>
2022-06-27 18:58:51 +02:00
Poolitzer 08e223ba90 API 6.1 (#3112)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2022-06-27 18:54:11 +02:00
Bibo-Joshi 01d643913e Stabilize CI (#3119) 2022-06-27 18:46:52 +02:00
Aditya Yadav 755945172d Add Additional Shortcut Methods to Chat (#3115) 2022-06-27 18:45:30 +02:00
dependabot[bot] 24b4de9f10 Bump pyupgrade from 2.32.1 to 2.34.0 (#3096)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-06-25 11:52:39 +02:00
David 76bfe8ceff Mermaid-based Example State Diagrams (#3090)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2022-06-24 18:15:10 +02:00
dependabot[bot] b498786d7c Bump furo from 2022.6.4 to 2022.6.4.1 (#3095)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-19 17:12:54 +02:00
dependabot[bot] bfe30048e8 Bump mypy from 0.960 to 0.961 (#3093)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-06-19 17:12:26 +02:00
Hinrich Mahler e25c523b69 Bump version to v20.0a1 2022-06-09 19:07:15 +02:00
Bibo-Joshi 67e7468366 Move Examples To Documentation (#3089) 2022-06-09 17:22:32 +02:00
Bibo-Joshi 11007c1715 Documentation Improvements (#3010, #3007, #3012, #3067, #3081, #3082)
Co-authored-by: KnorpelSenf <shtrog@gmail.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Poolitzer <github@poolitzer.eu>
Co-authored-by: Adi <71205439+Aditya-Rajgor@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-09 17:08:54 +02:00
Poolitzer d6e95f1974 Improve Some Unit Tests (#3026)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2022-06-09 17:07:28 +02:00
dependabot[bot] de28f177bd Update cachetools requirement from ~=5.1.0 to ~=5.2.0 (#3080)
* Update cachetools requirement from ~=5.1.0 to ~=5.2.0

Updates the requirements on [cachetools](https://github.com/tkem/cachetools) to permit the latest version.
- [Release notes](https://github.com/tkem/cachetools/releases)
- [Changelog](https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/tkem/cachetools/compare/v5.1.0...v5.2.0)

---
updated-dependencies:
- dependency-name: cachetools
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* update pre-commit as well

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-06-09 17:06:49 +02:00
Bibo-Joshi 63104ac0b3 Add Application.post_init (#3078) 2022-06-08 07:44:22 +02:00
Bibo-Joshi 22419c0464 Fix Non-Blocking Entry Point in ConversationHandler (#3068) 2022-06-07 17:48:26 +02:00
Bibo-Joshi 42276338b1 Add Arguments chat/user_id to CallbackContext And Example On Custom Webhook Setups (#3059)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2022-06-03 16:55:36 +02:00
dependabot[bot] 5f547f3725 Update httpx requirement from ~=0.22.0 to ~=0.23.0 (#3069)
* Update httpx requirement from ~=0.22.0 to ~=0.23.0

Updates the requirements on [httpx](https://github.com/encode/httpx) to permit the latest version.
- [Release notes](https://github.com/encode/httpx/releases)
- [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/httpx/compare/0.22.0...0.23.0)

---
updated-dependencies:
- dependency-name: httpx
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* update other places as well

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-06-02 10:10:08 +02:00
dependabot[bot] 8e7220e5db Update cachetools requirement from ~=5.0.0 to ~=5.1.0 (#3058)
* Update cachetools requirement from ~=5.0.0 to ~=5.1.0

Updates the requirements on [cachetools](https://github.com/tkem/cachetools) to permit the latest version.
- [Release notes](https://github.com/tkem/cachetools/releases)
- [Changelog](https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/tkem/cachetools/compare/v5.0.0...v5.1.0)

---
updated-dependencies:
- dependency-name: cachetools
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* update other places as well

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-06-02 10:09:05 +02:00
dependabot[bot] 977d56ab43 Bump mypy from 0.950 to 0.960 (#3070)
* Bump mypy from 0.950 to 0.960

Bumps [mypy](https://github.com/python/mypy) from 0.950 to 0.960.
- [Release notes](https://github.com/python/mypy/releases)
- [Commits](https://github.com/python/mypy/compare/v0.950...v0.960)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* update pre-commit as well

* fix type hint for CIRHandler.collect_additional_context

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2022-06-02 10:08:15 +02:00
Poolitzer 306cc64170 Don't Set Signal Handlers On Windows By Default (#3065) 2022-06-02 09:43:03 +02:00
dglitxh 42955ecddf Add Convenience Property Message.id (#3077) 2022-06-01 21:29:46 +02:00
Bibo-Joshi 67869693a7 Expose BaseRequest.parse_json_payload (#3072) 2022-06-01 21:26:18 +02:00
Bibo-Joshi 6ded9cc25c Drop InputFile.is_image (#3053) 2022-05-29 14:35:26 +02:00
Bibo-Joshi 5e0bcfbcc6 Drop Explicit Type conversions in __init__ s (#3056)
* Drop explicit type conversions in `__init__` s

* missed one
2022-05-26 19:16:30 +02:00
Bibo-Joshi a17a4c6c8f Handle List-Valued Attributes More Consistently (#3057) 2022-05-26 19:15:54 +02:00
Bibo-Joshi dc13b69dac Split {Command, Prefix}Handler And Make Attributes Immutable (#3045) 2022-05-26 11:10:00 +02:00
James Carl Necio 349baa0202 Align Behavior Of JobQueue.run_daily With cron (#3046) 2022-05-25 10:02:00 +02:00
Bibo-Joshi 5e24765bbc Escape Backslashes in escape_markdown (#3055) 2022-05-21 16:54:11 +02:00
Bibo-Joshi e10d933fde Add Example for WebApp (#3052) 2022-05-19 22:14:02 +02:00
Bibo-Joshi 2175af6abc Apply isort and Update pre-commit.ci Configuration (#3049) 2022-05-19 15:10:08 +02:00
Bibo-Joshi ca4e4c6280 Drop Support for ujson (#3037) 2022-05-19 12:47:53 +02:00
Bibo-Joshi d2cabcaa74 Adjust pre-commit Settings for isort (#3043) 2022-05-18 17:23:00 +02:00
tal66 076955d04d Make PTB Specific Keyword-Only Arguments for PTB Specific in Bot methods (#3035)
* Introduce keyword-only arguments in Bot methods

* partial code review fix

* tests, code rev changes

* flake8

* tests, code rev, more shortcut methods

* One more iteration on `check_shortcut_signature`

* Update tests/conftest.py

Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>

Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2022-05-18 17:18:44 +02:00
Bibo-Joshi c1041655f6 Adjust Equality Comparisons to Fit Bot API 6.0 (#3033) 2022-05-18 07:48:20 +02:00
dependabot[bot] 298c5fab3b Bump pylint from 2.13.8 to 2.13.9 (#3032)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-05-15 22:23:04 +02:00
Harshil 3013870c1f Add Version Check to Examples (#3036) 2022-05-15 14:08:40 +02:00
Bibo-Joshi 5e924014de Add Tuple Based Version Info and Rename telegram.bot_api_version to telegram.__bot_api_version__ (#3030) 2022-05-14 15:50:12 +02:00
Bibo-Joshi f792102212 Use Collection Instead of List and Tuple (#3025) 2022-05-13 16:41:34 +02:00
dependabot[bot] 72e357a780 Bump dessant/lock-threads from 2.0.1 to 3.0.0 (#2998)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-05-12 19:54:59 +02:00
Harshil 72c3eb857b Improve Type Annotations for CallbackContext and Move Default Type Alias to ContextTypes.DEFAULT_TYPE (#3017, #3023)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2022-05-12 19:36:25 +02:00
Aditya Yadav 1f7efe4519 Rename Job.context to Job.data (#3028) 2022-05-12 19:26:03 +02:00
Bibo-Joshi e47d18c9ec Remove Client-Side Parameter Validation (#3024) 2022-05-12 19:20:24 +02:00
Bibo-Joshi 65bbea780a Rename Handler to BaseHandler (#3019) 2022-05-12 18:18:40 +02:00
dependabot[bot] 23ed0880d2 Bump pyupgrade from 2.32.0 to 2.32.1 (#2999)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2022-05-10 18:35:59 +02:00
Bibo-Joshi a299867b1b Stabilize Application.run_* on Python 3.7 (#3009) 2022-05-10 18:35:20 +02:00
Harshil be8f4f7aad Don't Pass Default Values of Optional Parameters to Telegram (#2978) 2022-05-09 19:30:46 +02:00
Bibo-Joshi ea8089ad3e Ignore Code Style Commits in git blame (#3003) 2022-05-09 19:29:22 +02:00
Bibo-Joshi d917404de1 Adjust Tests to Changed API Behavior (#3002) 2022-05-07 21:47:50 +02:00
203 changed files with 5465 additions and 2533 deletions
+7
View File
@@ -0,0 +1,7 @@
# .git-blame-ignore-revs
# Use locally as `git blame file.py --ignore-revs-file .git-blame-ignore-revs`
# or configure git to always use it: `git config blame.ignoreRevsFile .git-blame-ignore-revs`
# First migration to code style Black (#2122)
264b2c9c72691c5937b80e84e061c52dd2d8861a
# Use Black more extensively (#2972)
950d9a0751d79b92d78ea44344ce3e3c5b3948f9
+8 -8
View File
@@ -263,19 +263,19 @@ break the API classes. For example:
self.last_name = last_name
.. _`Code of Conduct`: https://www.python.org/psf/codeofconduct/
.. _`Code of Conduct`: https://www.python.org/psf/conduct/
.. _`issue tracker`: https://github.com/python-telegram-bot/python-telegram-bot/issues
.. _`Telegram group`: https://telegram.me/pythontelegrambotgroup
.. _`PEP 8 Style Guide`: https://www.python.org/dev/peps/pep-0008/
.. _`sphinx`: http://sphinx-doc.org
.. _`Google Python Style Guide`: http://google.github.io/styleguide/pyguide.html
.. _`PEP 8 Style Guide`: https://peps.python.org/pep-0008/
.. _`sphinx`: https://www.sphinx-doc.org/en/master
.. _`Google Python Style Guide`: https://google.github.io/styleguide/pyguide.html
.. _`Google Python Style Docstrings`: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html
.. _AUTHORS.rst: ../AUTHORS.rst
.. _AUTHORS.rst: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/AUTHORS.rst
.. _`MyPy`: https://mypy.readthedocs.io/en/stable/index.html
.. _`here`: https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html
.. _`Black`: https://black.readthedocs.io/en/stable/index.html
.. _`popular editors`: https://black.readthedocs.io/en/stable/editor_integration.html
.. _`RTD`: https://python-telegram-bot.readthedocs.io/
.. _`RTD build`: https://python-telegram-bot.readthedocs.io/en/doc-fixes
.. _`popular editors`: https://black.readthedocs.io/en/stable/integrations/editors.html
.. _`RTD`: https://docs.python-telegram-bot.org/
.. _`RTD build`: https://docs.python-telegram-bot.org/en/doc-fixes
.. _`CSI`: https://standards.mousepawmedia.com/en/stable/csi.html
.. _`section`: #documenting
+29
View File
@@ -0,0 +1,29 @@
name: Check Links in Documentation
on:
schedule:
# First day of month at 05:46 in every 2nd month
- cron: '46 5 1 */2 *'
jobs:
test-sphinx-build:
name: test-sphinx-linkcheck
runs-on: ${{matrix.os}}
strategy:
matrix:
python-version: [3.7]
os: [ubuntu-latest]
fail-fast: False
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -W ignore -m pip install --upgrade pip
python -W ignore -m pip install -r requirements.txt
python -W ignore -m pip install -r requirements-dev.txt
python -W ignore -m pip install -r docs/requirements-docs.txt
- name: Check Links
run: sphinx-build docs/source docs/build/html -W --keep-going -j auto -b linkcheck
-5
View File
@@ -3,12 +3,10 @@ on:
pull_request:
branches:
- master
- v14
- doc-fixes
push:
branches:
- master
- v14
- doc-fixes
jobs:
@@ -22,9 +20,6 @@ jobs:
fail-fast: False
steps:
- uses: actions/checkout@v3
- name: Initialize vendored libs
run:
git submodule update --init --recursive
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
-16
View File
@@ -1,16 +0,0 @@
name: Warning maintainers
on:
pull_request_target:
paths: examples/**
permissions:
pull-requests: write
jobs:
job:
runs-on: ubuntu-latest
name: about example change
steps:
- name: running the check
uses: Poolitzer/notifier-action@master
with:
notify-message: Hey there. Relax, I am just a little warning for the maintainers to release directly after merging your PR, otherwise we have broken examples and people might get confused :)
repo-token: ${{ secrets.GITHUB_TOKEN }}
+3 -3
View File
@@ -9,10 +9,10 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2.0.1
- uses: dessant/lock-threads@v3.0.0
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: '7'
issue-inactive-days: '7'
issue-lock-reason: ''
pr-lock-inactive-days: '7'
pr-inactive-days: '7'
pr-lock-reason: ''
+14 -9
View File
@@ -5,6 +5,9 @@
ci:
autofix_prs: false
autoupdate_schedule: monthly
# We currently only need this behavior on the v13.x branch were we have the vendored urllib
# TODO: Remove once we discontinue v13
submodules: true
repos:
- repo: https://github.com/psf/black
@@ -19,7 +22,7 @@ repos:
hooks:
- id: flake8
- repo: https://github.com/PyCQA/pylint
rev: v2.13.8
rev: v2.13.9
hooks:
- id: pylint
files: ^(telegram|examples)/.*\.py$
@@ -30,13 +33,13 @@ repos:
- --jobs=0
additional_dependencies:
- httpx~=0.22.0
- httpx~=0.23.0
- tornado~=6.1
- APScheduler~=3.9.1
- cachetools~=5.0.0
- cachetools~=5.2.0
- . # this basically does `pip install -e .`
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.950
rev: v0.961
hooks:
- id: mypy
name: mypy-ptb
@@ -46,10 +49,10 @@ repos:
- types-pytz
- types-cryptography
- types-cachetools
- httpx~=0.22.0
- httpx~=0.23.0
- tornado~=6.1
- APScheduler~=3.9.1
- cachetools~=5.0.0
- cachetools~=5.2.0
- . # this basically does `pip install -e .`
- id: mypy
name: mypy-examples
@@ -60,10 +63,10 @@ repos:
additional_dependencies:
- tornado~=6.1
- APScheduler~=3.9.1
- cachetools~=5.0.0
- cachetools~=5.2.0
- . # this basically does `pip install -e .`
- repo: https://github.com/asottile/pyupgrade
rev: v2.32.0
rev: v2.34.0
hooks:
- id: pyupgrade
files: ^(telegram|examples|tests)/.*\.py$
@@ -74,4 +77,6 @@ repos:
hooks:
- id: isort
name: isort
args: ["--diff"] # -diff will not apply the changes, just show them
args:
- --diff
- --check
+5 -1
View File
@@ -15,8 +15,12 @@ formats:
# Optionally set the version of Python and requirements required to build your docs
python:
version: 3
install:
- method: pip
path: .
- requirements: docs/requirements-docs.txt
build:
os: ubuntu-20.04
tools:
python: "3" # latest stable cpython version
+4
View File
@@ -29,6 +29,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Balduro <https://github.com/Balduro>`_
- `Bibo-Joshi <https://github.com/Bibo-Joshi>`_
- `bimmlerd <https://github.com/bimmlerd>`_
- `cyc8 <https://github.com/cyc8>`_
- `d-qoi <https://github.com/d-qoi>`_
- `daimajia <https://github.com/daimajia>`_
- `Daniel Reed <https://github.com/nmlorg>`_
@@ -45,6 +46,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Evan Haberecht <https://github.com/habereet>`_
- `Evgeny Denisov <https://github.com/eIGato>`_
- `evgfilim1 <https://github.com/evgfilim1>`_
- `ExalFabu <https://github.com/ExalFabu>`_
- `franciscod <https://github.com/franciscod>`_
- `gamgi <https://github.com/gamgi>`_
- `Gauthamram Ravichandran <https://github.com/GauthamramRavichandran>`_
@@ -105,8 +107,10 @@ The following wonderful people contributed directly or indirectly to this projec
- `Vorobjev Simon <https://github.com/simonvorobjev>`_
- `Wagner Macedo <https://github.com/wagnerluis1982>`_
- `wjt <https://github.com/wjt>`_
- `Yaw Danso <https://github.com/dglitxh>`_
- `zeroone2numeral2 <https://github.com/zeroone2numeral2>`_
- `zeshuaro <https://github.com/zeshuaro>`_
- `zpavloudis <https://github.com/zpavloudis>`_
Please add yourself here alphabetically when you submit your first pull request.
+148 -4
View File
@@ -2,6 +2,150 @@
Changelog
=========
Version 20.0a2
==============
*Released 2022-06-27*
This is the technical changelog for version 20.0a2. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support for API 6.1 (`#3112`_)
New Features
------------
- Add Additional Shortcut Methods to ``Chat`` (`#3115`_)
- Mermaid-based Example State Diagrams (`#3090`_)
Minor Changes, Documentation Improvements and CI
------------------------------------------------
- Documentation Improvements (`#3103`_, `#3121`_, `#3098`_)
- Stabilize CI (`#3119`_)
- Bump ``pyupgrade`` from 2.32.1 to 2.34.0 (`#3096`_)
- Bump ``furo`` from 2022.6.4 to 2022.6.4.1 (`#3095`_)
- Bump ``mypy`` from 0.960 to 0.961 (`#3093`_)
.. _`#3112`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3112
.. _`#3115`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3115
.. _`#3090`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3090
.. _`#3103`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3103
.. _`#3121`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3121
.. _`#3098`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3098
.. _`#3119`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3119
.. _`#3096`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3096
.. _`#3095`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3095
.. _`#3093`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3093
Version 20.0a1
==============
*Released 2022-06-09*
This is the technical changelog for version 20.0a1. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes:
--------------
- Drop Support for ``ujson`` and instead ``BaseRequest.parse_json_payload`` (`#3037`_, `#3072`_)
- Drop ``InputFile.is_image`` (`#3053`_)
- Drop Explicit Type conversions in ``__init__`` s (`#3056`_)
- Handle List-Valued Attributes More Consistently (`#3057`_)
- Split ``{Command, Prefix}Handler`` And Make Attributes Immutable (`#3045`_)
- Align Behavior Of ``JobQueue.run_daily`` With ``cron`` (`#3046`_)
- Make PTB Specific Keyword-Only Arguments for PTB Specific in Bot methods (`#3035`_)
- Adjust Equality Comparisons to Fit Bot API 6.0 (`#3033`_)
- Add Tuple Based Version Info (`#3030`_)- Improve Type Annotations for ``CallbackContext`` and Move Default Type Alias to ``ContextTypes.DEFAULT_TYPE`` (`#3017`_, `#3023`_)
- Rename ``Job.context`` to ``Job.data`` (`#3028`_)
- Rename ``Handler`` to ``BaseHandler`` (`#3019`_)
New Features:
-------------
- Add ``Application.post_init`` (`#3078`_)
- Add Arguments ``chat/user_id`` to ``CallbackContext`` And Example On Custom Webhook Setups (`#3059`_)
- Add Convenience Property ``Message.id`` (`#3077`_)
- Add Example for ``WebApp`` (`#3052`_)
- Rename ``telegram.bot_api_version`` to ``telegram.__bot_api_version__`` (`#3030`_)
Bug Fixes:
----------
- Fix Non-Blocking Entry Point in ``ConversationHandler`` (`#3068`_)
- Escape Backslashes in ``escape_markdown`` (`#3055`_)
Dependencies:
-------------
- Update ``httpx`` requirement from ~=0.22.0 to ~=0.23.0 (`#3069`_)
- Update ``cachetools`` requirement from ~=5.0.0 to ~=5.2.0 (`#3058`_, `#3080`_)
Minor Changes, Documentation Improvements and CI:
-------------------------------------------------
- Move Examples To Documentation (`#3089`_)
- Documentation Improvements and Update Dependencies (`#3010`_, `#3007`_, `#3012`_, `#3067`_, `#3081`_, `#3082`_)
- Improve Some Unit Tests (`#3026`_)
- Update Code Quality dependencies (`#3070`_, `#3032`_,`#2998`_, `#2999`_)
- Don't Set Signal Handlers On Windows By Default (`#3065`_)
- Split ``{Command, Prefix}Handler`` And Make Attributes Immutable (`#3045`_)
- Apply ``isort`` and Update ``pre-commit.ci`` Configuration (`#3049`_)
- Adjust ``pre-commit`` Settings for ``isort`` (`#3043`_)
- Add Version Check to Examples (`#3036`_)
- Use ``Collection`` Instead of ``List`` and ``Tuple`` (`#3025`_)
- Remove Client-Side Parameter Validation (`#3024`_)
- Don't Pass Default Values of Optional Parameters to Telegram (`#2978`_)
- Stabilize ``Application.run_*`` on Python 3.7 (`#3009`_)
- Ignore Code Style Commits in ``git blame`` (`#3003`_)
- Adjust Tests to Changed API Behavior (`#3002`_)
.. _`#2978`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2978
.. _`#2998`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2998
.. _`#2999`: https://github.com/python-telegram-bot/python-telegram-bot/pull/2999
.. _`#3002`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3002
.. _`#3003`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3003
.. _`#3007`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3007
.. _`#3009`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3009
.. _`#3010`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3010
.. _`#3012`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3012
.. _`#3017`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3017
.. _`#3019`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3019
.. _`#3023`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3023
.. _`#3024`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3024
.. _`#3025`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3025
.. _`#3026`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3026
.. _`#3028`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3028
.. _`#3030`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3030
.. _`#3032`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3032
.. _`#3033`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3033
.. _`#3035`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3035
.. _`#3036`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3036
.. _`#3037`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3037
.. _`#3043`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3043
.. _`#3045`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3045
.. _`#3046`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3046
.. _`#3049`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3049
.. _`#3052`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3052
.. _`#3053`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3053
.. _`#3055`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3055
.. _`#3056`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3056
.. _`#3057`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3057
.. _`#3058`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3058
.. _`#3059`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3059
.. _`#3065`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3065
.. _`#3067`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3067
.. _`#3068`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3068
.. _`#3069`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3069
.. _`#3070`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3070
.. _`#3072`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3072
.. _`#3077`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3077
.. _`#3078`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3078
.. _`#3080`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3080
.. _`#3081`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3081
.. _`#3082`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3082
.. _`#3089`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3089
Version 20.0a0
==============
*Released 2022-05-06*
@@ -72,9 +216,9 @@ New Features:
by `DonalDuck004 <https://github.com/DonalDuck004>`__)
- Add Method ``drop_chat/user_data`` to ``Dispatcher`` and Persistence
(`#2852 <https://github.com/python-telegram-bot/python-telegram-bot/pull/2852>`__)
- Add methods ``ChatPermissions.{all, no}_permissions`` ([#2948]
- Add methods ``ChatPermissions.{all, no}_permissions`` (`#2948 <https://github.com/python-telegram-bot/python-telegram-bot/pull/2948>`__)
- Full Support for API 6.0
(`#2956 <https://github.com/python-telegram-bot/python-telegram-bot/pull/2956>`__)(https://github.com/python-telegram-bot/python-telegram-bot/pull/2948))
(`#2956 <https://github.com/python-telegram-bot/python-telegram-bot/pull/2956>`__)
- Add Python 3.10 to Test Suite
(`#2968 <https://github.com/python-telegram-bot/python-telegram-bot/pull/2968>`__)
@@ -1520,7 +1664,7 @@ Changes
- Lots of small improvements to our tests and documentation.
.. _`see docs`: http://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.dispatcher.html#telegram.ext.Dispatcher.add_handler
.. _`see docs`: https://docs.python-telegram-bot.org/en/stable/telegram.ext.dispatcher.html#telegram.ext.Dispatcher.add_handler
.. _`#777`: https://github.com/python-telegram-bot/python-telegram-bot/pull/777
.. _`#806`: https://github.com/python-telegram-bot/python-telegram-bot/pull/806
.. _`#766`: https://github.com/python-telegram-bot/python-telegram-bot/pull/766
@@ -1762,7 +1906,7 @@ Pre-version 7.0
- Implement Bot API 2.0
- Almost complete recode of ``Dispatcher``
- Please read the `Transistion Guide to 4.0 <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Transistion-guide-to-Version-4.0>`_
- Please read the `Transistion Guide to 4.0 <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Transition-guide-to-Version-4.0>`_
**2016-03-22**
+1 -1
View File
@@ -49,4 +49,4 @@ Project maintainers who do not follow or enforce the Code of Conduct in good fai
Attribution
===========
This Code of Conduct is adapted from the `Contributor Covenant <http://contributor-covenant.org>`_, version 1.4, available at `http://contributor-covenant.org/version/1/4 <http://contributor-covenant.org/version/1/4/>`_.
This Code of Conduct is adapted from the `Contributor Covenant <https://www.contributor-covenant.org>`_, version 1.4, available at `https://www.contributor-covenant.org/version/1/4 <https://www.contributor-covenant.org/version/1/4/>`_.
+14 -15
View File
@@ -1,7 +1,7 @@
..
Make sure to apply any changes to this file to README_RAW.rst as well!
.. image:: https://github.com/python-telegram-bot/logos/blob/master/logo-text/png/ptb-logo-text_768.png?raw=true
.. image:: https://raw.githubusercontent.com/python-telegram-bot/logos/master/logo-text/png/ptb-logo-text_768.png
:align: center
:target: https://python-telegram-bot.org
:alt: python-telegram-bot Logo
@@ -14,7 +14,7 @@
:target: https://pypi.org/project/python-telegram-bot/
:alt: Supported Python versions
.. image:: https://img.shields.io/badge/Bot%20API-6.0-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-6.1-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions
@@ -23,7 +23,7 @@
:alt: PyPi Package Monthly Download
.. image:: https://readthedocs.org/projects/python-telegram-bot/badge/?version=stable
:target: https://python-telegram-bot.readthedocs.io/en/stable/
:target: https://docs.python-telegram-bot.org/en/stable/
:alt: Documentation Status
.. image:: https://img.shields.io/pypi/l/python-telegram-bot.svg
@@ -35,15 +35,15 @@
:alt: Github Actions workflow
.. image:: https://codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg
:target: https://codecov.io/gh/python-telegram-bot/python-telegram-bot
:target: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot
:alt: Code coverage
.. image:: http://isitmaintained.com/badge/resolution/python-telegram-bot/python-telegram-bot.svg
:target: http://isitmaintained.com/project/python-telegram-bot/python-telegram-bot
.. image:: https://isitmaintained.com/badge/resolution/python-telegram-bot/python-telegram-bot.svg
:target: https://isitmaintained.com/project/python-telegram-bot/python-telegram-bot
:alt: Median time to resolve an issue
.. image:: https://api.codacy.com/project/badge/Grade/99d901eaa09b44b4819aec05c330c968
:target: https://www.codacy.com/app/python-telegram-bot/python-telegram-bot?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=python-telegram-bot/python-telegram-bot&amp;utm_campaign=Badge_Grade
:target: https://app.codacy.com/gh/python-telegram-bot/python-telegram-bot/dashboard
:alt: Code quality: Codacy
.. image:: https://deepsource.io/gh/python-telegram-bot/python-telegram-bot.svg/?label=active+issues
@@ -93,7 +93,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
Telegram API support
====================
All types and methods of the Telegram Bot API **6.0** are supported.
All types and methods of the Telegram Bot API **6.1** are supported.
Installing
==========
@@ -121,9 +121,9 @@ Dependencies & Their Versions
However, for some features using a 3rd party library is more sane than implementing the functionality again.
The dependencies are:
* `httpx ~= 0.22.0 <https://www.python-httpx.org>`_ for ``telegram.request.HTTPXRequest``, the default networking backend
* `httpx ~= 0.23.0 <https://www.python-httpx.org>`_ for ``telegram.request.HTTPXRequest``, the default networking backend
* `tornado~=6.1 <https://www.tornadoweb.org/en/stable/>`_ for ``telegram.ext.Updater.start_webhook``
* `cachetools~=5.0.0 <https://cachetools.readthedocs.io/en/latest/>`_ for ``telegram.ext.CallbackDataCache``
* `cachetools~=5.2.0 <https://cachetools.readthedocs.io/en/latest/>`_ for ``telegram.ext.CallbackDataCache``
* `APScheduler~=3.9.1 <https://apscheduler.readthedocs.io/en/3.x/>`_ for ``telegram.ext.JobQueue``
``python-telegram-bot`` is most useful when used along with additional libraries.
@@ -136,8 +136,7 @@ Optional Dependencies
PTB can be installed with optional dependencies:
* ``pip install python-telegram-bot[passport]`` installs the `cryptography>=3.0 <https://cryptography.io>`_ library. Use this, if you want to use Telegram Passport related functionality.
* ``pip install python-telegram-bot[json]`` installs the `ujson>=4.0.0 <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[passport]`` installs the `cryptography>=3.0 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
* ``pip install python-telegram-bot[socks]`` installs ``httpx[socks]``. Use this, if you want to work behind a Socks5 server.
Quick Start
@@ -149,10 +148,10 @@ Moreover, the `Tutorial: Your first Bot <https://github.com/python-telegram-bot/
Resources
=========
- The `package documentation <https://python-telegram-bot.readthedocs.io/>`_ is the technical reference for ``python-telegram-bot``.
It contains descriptions of all available classes, modules, methods and arguments.
- The `package documentation <https://docs.python-telegram-bot.org/>`_ is the technical reference for ``python-telegram-bot``.
It contains descriptions of all available classes, modules, methods and arguments as well as the `changelog <https://docs.python-telegram-bot.org/changelog.html>`_.
- The `wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/>`_ is home to number of more elaborate introductions of the different features of ``python-telegram-bot`` and other useful resources that go beyond the technical documentation.
- Our `examples directory <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/README.md>`_ contains several examples that showcase the different features of both the Bot API and ``python-telegram-bot``.
- Our `examples section <https://docs.python-telegram-bot.org/examples.html>`_ contains several examples that showcase the different features of both the Bot API and ``python-telegram-bot``.
Even if it is not your approach for learning, please take a look at ``echobot.py``. It is the de facto base for most of the bots out there.
The code for these examples is released to the public domain, so you can start by grabbing the code and building on top of it.
- The `official Telegram Bot API documentation <https://core.telegram.org/bots/api>`_ is of course always worth a read.
+13 -14
View File
@@ -14,7 +14,7 @@
:target: https://pypi.org/project/python-telegram-bot-raw/
:alt: Supported Python versions
.. image:: https://img.shields.io/badge/Bot%20API-6.0-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-6.1-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions
@@ -23,7 +23,7 @@
:alt: PyPi Package Monthly Download
.. image:: https://readthedocs.org/projects/python-telegram-bot/badge/?version=stable
:target: https://python-telegram-bot.readthedocs.io/
:target: https://docs.python-telegram-bot.org/
:alt: Documentation Status
.. image:: https://img.shields.io/pypi/l/python-telegram-bot-raw.svg
@@ -34,16 +34,16 @@
:target: https://github.com/python-telegram-bot/python-telegram-bot/
:alt: Github Actions workflow
.. image:: https://codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg
:target: https://codecov.io/gh/python-telegram-bot/python-telegram-bot
.. image:: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot
:target: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot
:alt: Code coverage
.. image:: http://isitmaintained.com/badge/resolution/python-telegram-bot/python-telegram-bot.svg
:target: http://isitmaintained.com/project/python-telegram-bot/python-telegram-bot
.. image:: https://isitmaintained.com/badge/resolution/python-telegram-bot/python-telegram-bot.svg
:target: https://isitmaintained.com/project/python-telegram-bot/python-telegram-bot
:alt: Median time to resolve an issue
.. image:: https://api.codacy.com/project/badge/Grade/99d901eaa09b44b4819aec05c330c968
:target: https://www.codacy.com/app/python-telegram-bot/python-telegram-bot?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=python-telegram-bot/python-telegram-bot&amp;utm_campaign=Badge_Grade
:target: https://app.codacy.com/gh/python-telegram-bot/python-telegram-bot/dashboard
:alt: Code quality: Codacy
.. image:: https://deepsource.io/gh/python-telegram-bot/python-telegram-bot.svg/?label=active+issues
@@ -89,7 +89,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
Telegram API support
====================
All types and methods of the Telegram Bot API **6.0** are supported.
All types and methods of the Telegram Bot API **6.1** are supported.
Installing
==========
@@ -122,7 +122,7 @@ Dependencies & Their Versions
However, for some features using a 3rd party library is more sane than implementing the functionality again.
The dependencies are:
* `httpx ~= 0.22.0 <https://www.python-httpx.org>`_ for ``telegram.request.HTTPXRequest``, the default networking backend
* `httpx ~= 0.23.0 <https://www.python-httpx.org>`_ for ``telegram.request.HTTPXRequest``, the default networking backend
``python-telegram-bot`` is most useful when used along with additional libraries.
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the dependencies.
@@ -134,8 +134,7 @@ Optional Dependencies
``python-telegram-bot-raw`` 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[json]`` 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[passport]`` installs the `cryptography <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
* ``pip install python-telegram-bot[socks]`` installs the `PySocks <https://pypi.org/project/PySocks/>`_ library. Use this, if you want to work behind a Socks5 server.
Quick Start
@@ -146,10 +145,10 @@ Our Wiki contains an `Introduction to the API <https://github.com/python-telegra
Resources
=========
- The `package documentation <https://python-telegram-bot.readthedocs.io/>`_ is the technical reference for ``python-telegram-bot``.
It contains descriptions of all available classes, modules, methods and arguments.
- The `package documentation <https://docs.python-telegram-bot.org/>`_ is the technical reference for ``python-telegram-bot``.
It contains descriptions of all available classes, modules, methods and arguments as well as the `changelog <https://docs.python-telegram-bot.org/changelog.html>`_.
- The `wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/>`_ is home to number of more elaborate introductions of the different features of ``python-telegram-bot`` and other useful resources that go beyond the technical documentation.
- Our `examples directory <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/README.md>`_ contains several examples that showcase the different features of both the Bot API and ``python-telegram-bot``.
- Our `examples section <https://docs.python-telegram-bot.org/examples.html>`_ contains several examples that showcase the different features of both the Bot API and ``python-telegram-bot``.
Even if it is not your approach for learning, please take a look at ``echobot.py``. It is the de facto base for most of the bots out there.
The code for these examples is released to the public domain, so you can start by grabbing the code and building on top of it.
- The `official Telegram Bot API documentation <https://core.telegram.org/bots/api>`_ is of course always worth a read.
+4 -6
View File
@@ -1,7 +1,5 @@
sphinx==4.5.0
sphinx==5.0.2
sphinx-pypi-upload
furo==2022.04.07
# Can be replaced with a sphinx-paramlinks==... dependency once a version is released that
# includes the commit mentioned below and maybe even
# https://github.com/sqlalchemyorg/sphinx-paramlinks/pull/14
git+https://github.com/sqlalchemyorg/sphinx-paramlinks.git@acedb03149e3f87ff599174b033754c2f58f1c95
furo==2022.6.21
sphinx-paramlinks==0.5.4
sphinxcontrib-mermaid==0.7.1
@@ -0,0 +1,3 @@
.mermaid svg {
height: auto;
}
+2
View File
@@ -263,6 +263,8 @@
:align: left
:widths: 1 4
* - :meth:`~telegram.Bot.create_invoice_link`
- Used to generate an HTTP link for an invoice
* - :meth:`~telegram.Bot.close`
- Used for closing server instance when switching to another local server
* - :meth:`~telegram.Bot.log_out`
+65 -185
View File
@@ -1,16 +1,3 @@
# -*- coding: utf-8 -*-
#
# Python Telegram Bot documentation build configuration file, created by
# sphinx-quickstart on Mon Aug 10 22:25:07 2015.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import inspect
import os
import re
@@ -32,6 +19,19 @@ from sphinx.util import logging
sys.path.insert(0, os.path.abspath("../.."))
# -- General configuration ------------------------------------------------
# General information about the project.
project = "python-telegram-bot"
copyright = "2015-2022, Leandro Toledo"
author = "Leandro Toledo"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = "20.0a2" # telegram.__version__[:3]
# The full version, including alpha/beta/rc tags.
release = "20.0a2" # telegram.__version__
# If your documentation needs a minimal Sphinx version, state it here.
needs_sphinx = "4.5.0"
@@ -45,6 +45,7 @@ extensions = [
"sphinx.ext.intersphinx",
"sphinx.ext.linkcode",
"sphinx_paramlinks",
"sphinxcontrib.mermaid",
]
# Use intersphinx to reference the python builtin library docs
@@ -53,76 +54,49 @@ intersphinx_mapping = {
"APScheduler": ("https://apscheduler.readthedocs.io/en/3.x/", None),
}
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
source_suffix = ".rst"
# The master toctree document.
master_doc = "index"
# -- Extension settings ------------------------------------------------
napoleon_use_admonition_for_examples = True
# 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"]
# Fail on warnings & unresolved references etc
nitpicky = True
# Paramlink style
paramlinks_hyperlink_param = "name"
# Linkcheck settings
linkcheck_ignore = [
# Let's not check issue/PR links - that's wasted resources
r"http(s)://github\.com/python-telegram-bot/python-telegram-bot/(issues|pull)/\d+/?",
# For some reason linkcheck has a problem with these two:
re.escape("https://github.com/python-telegram-bot/python-telegram-bot/discussions/new"),
re.escape("https://github.com/python-telegram-bot/python-telegram-bot/issues/new"),
# Anchors are apparently inserted by GitHub dynamically, so let's skip checking them
"https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples#",
r"https://github\.com/python-telegram-bot/python-telegram-bot/wiki/[\w\-_,]+\#",
]
linkcheck_allowed_redirects = {
# Redirects to the default version are okay
r"https://docs\.python-telegram-bot\.org/.*": r"https://docs\.python-telegram-bot\.org/en/[\w\d\.]+/.*",
# pre-commit.ci always redirects to the latest run
re.escape(
"https://results.pre-commit.ci/latest/github/python-telegram-bot/python-telegram-bot/master"
): r"https://results\.pre-commit\.ci/run/github/.*",
}
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = ".rst"
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = "index"
# General information about the project.
project = "python-telegram-bot"
copyright = "2015-2021, Leandro Toledo"
author = "Leandro Toledo"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = "20.0a0" # telegram.__version__[:3]
# The full version, including alpha/beta/rc tags.
release = "20.0a0" # telegram.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all
# documents.
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
@@ -130,16 +104,9 @@ pygments_style = "sphinx"
# Decides the language used for syntax highlighting of code blocks.
highlight_language = "python3"
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
@@ -228,16 +195,10 @@ html_theme_options = {
],
}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
html_title = f"python-telegram-bot<br> v{version}"
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = "ptb-logo_1024.png"
@@ -251,72 +212,19 @@ html_favicon = "ptb-logo_1024.ico"
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
html_css_files = ["style_external_link.css"]
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
# html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
# If false, no index is generated.
# html_use_index = True
# If true, the index is split into individual pages for each letter.
# html_split_index = False
# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
# html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
# html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
# html_search_scorer = 'scorer.js'
html_css_files = [
"style_external_link.css",
"style_mermaid_diagrams.css",
]
html_permalinks_icon = "" # Furo's default permalink icon is `#`` which doesn't look great imo.
# Output file base name for HTML help builder.
htmlhelp_basename = "python-telegram-bot-doc"
# The base URL which points to the root of the HTML documentation. It is used to indicate the
# location of document using The Canonical Link Relation. Default: ''.
html_baseurl = "https://docs.python-telegram-bot.org"
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
@@ -343,32 +251,12 @@ latex_documents = [
# the title page.
latex_logo = "ptb-logo_1024.png"
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
# latex_appendices = []
# If false, no module index is generated.
# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [(master_doc, "python-telegram-bot", "python-telegram-bot Documentation", [author], 1)]
# If true, show URL addresses after external links.
# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
@@ -387,22 +275,6 @@ texinfo_documents = [
),
]
# Documents to append as an appendix to all manuals.
# texinfo_appendices = []
# If false, no module index is generated.
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
# texinfo_no_detailmenu = False
# Napoleon stuff
napoleon_use_admonition_for_examples = True
# -- script stuff --------------------------------------------------------
# get the sphinx(!) logger
@@ -444,9 +316,17 @@ class TGConstXRefRole(PyXRefRole):
if isinstance(value, telegram.constants.FileSizeLimit):
return f"{int(value.value / 1e6)} MB", target
return repr(value.value), target
# Just for Bot API version number auto add in constants:
if isinstance(value, str) and target == "telegram.constants.BOT_API_VERSION":
# Just for (Bot API) versions number auto add in constants:
if isinstance(value, str) and target in (
"telegram.constants.BOT_API_VERSION",
"telegram.__version__",
):
return value, target
if isinstance(value, tuple) and target in (
"telegram.constants.BOT_API_VERSION_INFO",
"telegram.__version_info__",
):
return repr(value), target
sphinx_logger.warning(
f"%s:%d: WARNING: Did not convert reference %s. :{CONSTANTS_ROLE}: is not supposed"
" to be used with this type of target.",
@@ -0,0 +1,7 @@
``arbitrarycallbackdatabot.py``
===============================
.. literalinclude:: ../../examples/arbitrarycallbackdatabot.py
:language: python
:linenos:
+7
View File
@@ -0,0 +1,7 @@
``chatmemberbot.py``
====================
.. literalinclude:: ../../examples/chatmemberbot.py
:language: python
:linenos:
+7
View File
@@ -0,0 +1,7 @@
``contexttypesbot.py``
======================
.. literalinclude:: ../../examples/contexttypesbot.py
:language: python
:linenos:
+13
View File
@@ -0,0 +1,13 @@
``conversationbot.py``
======================
.. literalinclude:: ../../examples/conversationbot.py
:language: python
:linenos:
.. _conversationbot-diagram:
State Diagram
-------------
.. mermaid:: ../../examples/conversationbot.mmd
+13
View File
@@ -0,0 +1,13 @@
``conversationbot2.py``
=======================
.. literalinclude:: ../../examples/conversationbot2.py
:language: python
:linenos:
.. _conversationbot2-diagram:
State Diagram
-------------
.. mermaid:: ../../examples/conversationbot2.mmd
@@ -0,0 +1,7 @@
``customwebhookbot.py``
=======================
.. literalinclude:: ../../examples/customwebhookbot.py
:language: python
:linenos:
+7
View File
@@ -0,0 +1,7 @@
``deeplinking.py``
==================
.. literalinclude:: ../../examples/deeplinking.py
:language: python
:linenos:
+7
View File
@@ -0,0 +1,7 @@
``echobot.py``
==============
.. literalinclude:: ../../examples/echobot.py
:language: python
:linenos:
+7
View File
@@ -0,0 +1,7 @@
``errorhandlerbot.py``
======================
.. literalinclude:: ../../examples/errorhandlerbot.py
:language: python
:linenos:
+7
View File
@@ -0,0 +1,7 @@
``inlinebot.py``
================
.. literalinclude:: ../../examples/inlinebot.py
:language: python
:linenos:
+7
View File
@@ -0,0 +1,7 @@
``inlinekeyboard.py``
=====================
.. literalinclude:: ../../examples/inlinekeyboard.py
:language: python
:linenos:
+7
View File
@@ -0,0 +1,7 @@
``inlinekeyboard2.py``
======================
.. literalinclude:: ../../examples/inlinekeyboard2.py
:language: python
:linenos:
@@ -0,0 +1,13 @@
``nestedconversationbot.py``
============================
.. literalinclude:: ../../examples/nestedconversationbot.py
:language: python
:linenos:
.. _nestedconversationbot-diagram:
State Diagram
-------------
.. mermaid:: ../../examples/nestedconversationbot.mmd
+16
View File
@@ -0,0 +1,16 @@
``passportbot.py``
==================
.. literalinclude:: ../../examples/passportbot.py
:language: python
:linenos:
.. _passportbot-html:
HTML Page
---------
.. literalinclude:: ../../examples/passportbot.html
:language: html
:linenos:
+7
View File
@@ -0,0 +1,7 @@
``paymentbot.py``
=================
.. literalinclude:: ../../examples/paymentbot.py
:language: python
:linenos:
@@ -0,0 +1,7 @@
``persistentconversationbot.py``
================================
.. literalinclude:: ../../examples/persistentconversationbot.py
:language: python
:linenos:
+7
View File
@@ -0,0 +1,7 @@
``pollbot.py``
==============
.. literalinclude:: ../../examples/pollbot.py
:language: python
:linenos:
+11
View File
@@ -0,0 +1,11 @@
`rawapibot.py`
==============
This example uses only the pure, "bare-metal" API wrapper.
.. literalinclude:: ../../examples/rawapibot.py
:language: python
:linenos:
+194
View File
@@ -0,0 +1,194 @@
Examples
========
In this section we display small examples to show what a bot written with
``python-telegram-bot`` looks like.
Some bots focus on one specific
aspect of the Telegram Bot API while others focus on one of the
mechanics of this library. Except for the
:any:`examples.rawapibot` example, they all use the high-level
framework this library provides with the
:any:`telegram.ext <telegram.ext>` submodule.
All examples are licensed under the `CC0
License <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/LICENSE.txt>`__
and are therefore fully dedicated to the public domain. You can use them
as the base for your own bots without worrying about copyrights.
Do note that we ignore one pythonic convention. Best practice would
dictate, in many handler callbacks function signatures, to replace the
argument ``context`` with an underscore, since ``context`` is an unused
local variable in those callbacks. However, since these are examples and
not having a name for that argument confuses beginners, we decided to
have it present.
:any:`examples.echobot`
-----------------------
This is probably the base for most of the bots made with
``python-telegram-bot``. It simply replies to each text message with a
message that contains the same text.
:any:`examples.timerbot`
------------------------
This bot uses the
:class:`telegram.ext.JobQueue`
class to send timed messages. The user sets a timer by using ``/set``
command with a specific time, for example ``/set 30``. The bot then sets
up a job to send a message to that user after 30 seconds. The user can
also cancel the timer by sending ``/unset``. To learn more about the
``JobQueue``, read `this wiki
article <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-JobQueue>`__.
:any:`examples.conversationbot`
-------------------------------
A common task for a bot is to ask information from the user. In v5.0 of
this library, we introduced the
:class:`telegram.ext.ConversationHandler`
for that exact purpose. This example uses it to retrieve
user-information in a conversation-like style. To get a better
understanding, take a look at the :ref:`state diagrem <conversationbot-diagram>`.
:any:`examples.conversationbot2`
--------------------------------
A more complex example of a bot that uses the ``ConversationHandler``.
It is also more confusing. Good thing there is a :ref:`fancy state diagram <conversationbot2-diagram>`.
for this one, too!
:any:`examples.nestedconversationbot`
-------------------------------------
A even more complex example of a bot that uses the nested
``ConversationHandler``\ s. While its certainly not that complex that
you couldnt built it without nested ``ConversationHanldler``\ s, it
gives a good impression on how to work with them. Of course, there is a
:ref:`fancy state diagram <nestedconversationbot-diagram>`
for this example, too!
:any:`examples.persistentconversationbot`
-----------------------------------------
A basic example of a bot store conversation state and user_data over
multiple restarts.
:any:`examples.inlinekeyboard`
------------------------------
This example sheds some light on inline keyboards, callback queries and
message editing. A wiki site explaining this examples lives
`here <https://github.com/python-telegram-bot/python-telegram-bot/wiki/InlineKeyboard-Example>`__.
:any:`examples.inlinekeyboard2`
-------------------------------
A more complex example about inline keyboards, callback queries and
message editing. This example showcases how an interactive menu could be
build using inline keyboards.
:any:`examples.deeplinking`
---------------------------
A basic example on how to use deeplinking with inline keyboards.
:any:`examples.inlinebot`
-------------------------
A basic example of an `inline
bot <https://core.telegram.org/bots/inline>`__. Dont forget to enable
inline mode with `@BotFather <https://telegram.me/BotFather>`_.
:any:`examples.pollbot`
-----------------------
This example sheds some light on polls, poll answers and the
corresponding handlers.
:any:`examples.passportbot`
---------------------------
A basic example of a bot that can accept passports. Use in combination
with the :ref:`HTML page <passportbot-html>`.
Dont forget to enable and configure payments with
`@BotFather <https://telegram.me/BotFather>`_. Check out this
`guide <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Telegram-Passport>`__
on Telegram passports in PTB.
:any:`examples.paymentbot`
--------------------------
A basic example of a bot that can accept payments. Dont forget to
enable and configure payments with
`@BotFather <https://telegram.me/BotFather>`_.
:any:`examples.errorhandlerbot`
-------------------------------
A basic example on how to set up a custom error handler.
:any:`examples.chatmemberbot`
-----------------------------
A basic example on how ``(my_)chat_member`` updates can be used.
:any:`examples.webappbot`
-------------------------
A basic example of how `Telegram
WebApps <https://core.telegram.org/bots/webapps>`__ can be used. Use in
combination with the :ref:`HTML page <webappbot-html>`.
For your convenience, this file is hosted by the PTB team such that you
dont need to host it yourself. Uses the
`iro.js <https://iro.js.org>`__ JavaScript library to showcase a
user interface that is hard to achieve with native Telegram
functionality.
:any:`examples.contexttypesbot`
-------------------------------
This example showcases how ``telegram.ext.ContextTypes`` can be used to
customize the ``context`` argument of handler and job callbacks.
:any:`examples.customwebhookbot`
--------------------------------
This example showcases how a custom webhook setup can be used in
combination with ``telegram.ext.Application``.
:any:`examples.arbitrarycallbackdatabot`
----------------------------------------
This example showcases how PTBs “arbitrary callback data” feature can be
used.
Pure API
--------
The :any:`examples.rawapibot` example example uses only the pure, “bare-metal” API wrapper.
.. toctree::
:hidden:
examples.arbitrarycallbackdatabot
examples.chatmemberbot
examples.contexttypesbot
examples.conversationbot
examples.conversationbot2
examples.customwebhookbot
examples.deeplinking
examples.echobot
examples.errorhandlerbot
examples.inlinebot
examples.inlinekeyboard
examples.inlinekeyboard2
examples.nestedconversationbot
examples.passportbot
examples.paymentbot
examples.persistentconversationbot
examples.pollbot
examples.rawapibot
examples.timerbot
examples.webappbot
+7
View File
@@ -0,0 +1,7 @@
``timerbot.py``
===============
.. literalinclude:: ../../examples/timerbot.py
:language: python
:linenos:
+16
View File
@@ -0,0 +1,16 @@
``webappbot.py``
================
.. literalinclude:: ../../examples/webappbot.py
:language: python
:linenos:
.. _webappbot-html:
HTML Page
---------
.. literalinclude:: ../../examples/webappbot.html
:language: html
:linenos:
+8 -1
View File
@@ -5,7 +5,7 @@
.. include:: ../../README.rst
.. The toctrees are hidden such that they don't reander on the start page but still include the contents into the documentation.
.. The toctrees are hidden such that they don't render on the start page but still include the contents into the documentation.
.. toctree::
:hidden:
@@ -16,6 +16,13 @@
telegram_auxil
Telegrams Bot API Docs <https://core.telegram.org/bots/api>
.. toctree::
:hidden:
:caption: Resources
examples
Wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki>
.. toctree::
:hidden:
:caption: Project
+6
View File
@@ -0,0 +1,6 @@
telegram.ext.BaseHandler
========================
.. autoclass:: telegram.ext.BaseHandler
:members:
:show-inheritance:
-6
View File
@@ -1,6 +0,0 @@
telegram.ext.Handler
====================
.. autoclass:: telegram.ext.Handler
:members:
:show-inheritance:
+8 -8
View File
@@ -3,32 +3,32 @@ telegram.ext package
.. toctree::
telegram.ext.extbot
telegram.ext.applicationbuilder
telegram.ext.application
telegram.ext.applicationbuilder
telegram.ext.applicationhandlerstop
telegram.ext.updater
telegram.ext.callbackcontext
telegram.ext.job
telegram.ext.jobqueue
telegram.ext.contexttypes
telegram.ext.defaults
telegram.ext.extbot
telegram.ext.job
telegram.ext.jobqueue
telegram.ext.updater
Handlers
--------
.. toctree::
telegram.ext.handler
telegram.ext.basehandler
telegram.ext.callbackqueryhandler
telegram.ext.chatjoinrequesthandler
telegram.ext.chatmemberhandler
telegram.ext.choseninlineresulthandler
telegram.ext.commandhandler
telegram.ext.conversationhandler
telegram.ext.filters
telegram.ext.inlinequeryhandler
telegram.ext.messagehandler
telegram.ext.filters
telegram.ext.pollanswerhandler
telegram.ext.pollhandler
telegram.ext.precheckoutqueryhandler
@@ -44,9 +44,9 @@ Persistence
.. toctree::
telegram.ext.basepersistence
telegram.ext.dictpersistence
telegram.ext.persistenceinput
telegram.ext.picklepersistence
telegram.ext.dictpersistence
Arbitrary Callback Data
-----------------------
+38 -29
View File
@@ -1,6 +1,15 @@
telegram package
================
Version Constants
-----------------
.. automodule:: telegram
:members: __version__, __version_info__, __bot_api_version__, __bot_api_version_info__
Available Types
---------------
.. toctree::
telegram.animation
@@ -8,13 +17,13 @@ telegram package
telegram.bot
telegram.botcommand
telegram.botcommandscope
telegram.botcommandscopedefault
telegram.botcommandscopeallprivatechats
telegram.botcommandscopeallgroupchats
telegram.botcommandscopeallchatadministrators
telegram.botcommandscopeallgroupchats
telegram.botcommandscopeallprivatechats
telegram.botcommandscopechat
telegram.botcommandscopechatadministrators
telegram.botcommandscopechatmember
telegram.botcommandscopedefault
telegram.callbackquery
telegram.chat
telegram.chatadministratorrights
@@ -22,12 +31,12 @@ telegram package
telegram.chatjoinrequest
telegram.chatlocation
telegram.chatmember
telegram.chatmemberowner
telegram.chatmemberadministrator
telegram.chatmembermember
telegram.chatmemberrestricted
telegram.chatmemberleft
telegram.chatmemberbanned
telegram.chatmemberleft
telegram.chatmembermember
telegram.chatmemberowner
telegram.chatmemberrestricted
telegram.chatmemberupdated
telegram.chatpermissions
telegram.chatphoto
@@ -55,15 +64,15 @@ telegram package
telegram.menubuttonwebapp
telegram.message
telegram.messageautodeletetimerchanged
telegram.messageid
telegram.messageentity
telegram.messageid
telegram.photosize
telegram.poll
telegram.pollanswer
telegram.polloption
telegram.proximityalerttriggered
telegram.replykeyboardremove
telegram.replykeyboardmarkup
telegram.replykeyboardremove
telegram.sentwebappmessage
telegram.telegramobject
telegram.update
@@ -86,15 +95,16 @@ Stickers
.. toctree::
telegram.maskposition
telegram.sticker
telegram.stickerset
telegram.maskposition
Inline Mode
-----------
.. toctree::
telegram.choseninlineresult
telegram.inlinequery
telegram.inlinequeryresult
telegram.inlinequeryresultarticle
@@ -123,29 +133,28 @@ Inline Mode
telegram.inputvenuemessagecontent
telegram.inputcontactmessagecontent
telegram.inputinvoicemessagecontent
telegram.choseninlineresult
Payments
--------
.. toctree::
telegram.labeledprice
telegram.invoice
telegram.shippingaddress
telegram.labeledprice
telegram.orderinfo
telegram.shippingoption
telegram.successfulpayment
telegram.shippingquery
telegram.precheckoutquery
telegram.shippingaddress
telegram.shippingoption
telegram.shippingquery
telegram.successfulpayment
Games
-----
.. toctree::
telegram.game
telegram.callbackgame
telegram.game
telegram.gamehighscore
Passport
@@ -153,25 +162,25 @@ Passport
.. toctree::
telegram.credentials
telegram.datacredentials
telegram.encryptedcredentials
telegram.encryptedpassportelement
telegram.filecredentials
telegram.iddocumentdata
telegram.passportdata
telegram.passportelementerror
telegram.passportelementerrordatafield
telegram.passportelementerrorfile
telegram.passportelementerrorfiles
telegram.passportelementerrorreverseside
telegram.passportelementerrorfrontside
telegram.passportelementerrordatafield
telegram.passportelementerrorreverseside
telegram.passportelementerrorselfie
telegram.passportelementerrortranslationfile
telegram.passportelementerrortranslationfiles
telegram.passportelementerrorunspecified
telegram.credentials
telegram.datacredentials
telegram.securedata
telegram.securevalue
telegram.filecredentials
telegram.iddocumentdata
telegram.passportfile
telegram.personaldetails
telegram.residentialaddress
telegram.passportdata
telegram.passportfile
telegram.encryptedpassportelement
telegram.encryptedcredentials
telegram.securedata
telegram.securevalue
+2 -58
View File
@@ -1,61 +1,5 @@
# Examples
In this folder are small examples to show what a bot written with `python-telegram-bot` looks like. Some bots focus on one specific aspect of the Telegram Bot API while others focus on one of the mechanics of this library. Except for the [`rawapibot.py`](#pure-api) example, they all use the high-level framework this library provides with the [`telegram.ext`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.html) submodule.
A description of the examples in this directory can be found in the [documentation](https://docs.python-telegram-bot.org/examples.html).
All examples are licensed under the [CC0 License](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/LICENSE.txt) and are therefore fully dedicated to the public domain. You can use them as the base for your own bots without worrying about copyrights.
Do note that we ignore one pythonic convention. Best practice would dictate, in many handler callbacks function signatures, to replace the argument `context` with an underscore, since `context` is an unused local variable in those callbacks. However, since these are examples and not having a name for that argument confuses beginners, we decided to have it present.
### [`echobot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/echobot.py)
This is probably the base for most of the bots made with `python-telegram-bot`. It simply replies to each text message with a message that contains the same text.
### [`timerbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/timerbot.py)
This bot uses the [`JobQueue`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.jobqueue.html) class to send timed messages. The user sets a timer by using `/set` command with a specific time, for example `/set 30`. The bot then sets up a job to send a message to that user after 30 seconds. The user can also cancel the timer by sending `/unset`. To learn more about the `JobQueue`, read [this wiki article](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-JobQueue).
### [`conversationbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot.py)
A common task for a bot is to ask information from the user. In v5.0 of this library, we introduced the [`ConversationHandler`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.conversationhandler.html) for that exact purpose. This example uses it to retrieve user-information in a conversation-like style. To get a better understanding, take a look at the [state diagram](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot.png).
### [`conversationbot2.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot2.py)
A more complex example of a bot that uses the `ConversationHandler`. It is also more confusing. Good thing there is a [fancy state diagram](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot2.png) for this one, too!
### [`nestedconversationbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/nestedconversationbot.py)
A even more complex example of a bot that uses the nested `ConversationHandler`s. While it's certainly not that complex that you couldn't built it without nested `ConversationHanldler`s, it gives a good impression on how to work with them. Of course, there is a [fancy state diagram](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/nestedconversationbot.png) for this example, too!
### [`persistentconversationbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/persistentconversationbot.py)
A basic example of a bot store conversation state and user_data over multiple restarts.
### [`inlinekeyboard.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/inlinekeyboard.py)
This example sheds some light on inline keyboards, callback queries and message editing. A wiki site explaining this examples lives [here](https://github.com/python-telegram-bot/python-telegram-bot/wiki/InlineKeyboard-Example).
### [`inlinekeyboard2.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/inlinekeyboard2.py)
A more complex example about inline keyboards, callback queries and message editing. This example showcases how an interactive menu could be build using inline keyboards.
### [`deeplinking.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/deeplinking.py)
A basic example on how to use deeplinking with inline keyboards.
### [`inlinebot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/inlinebot.py)
A basic example of an [inline bot](https://core.telegram.org/bots/inline). Don't forget to enable inline mode with [@BotFather](https://telegram.me/BotFather).
### [`pollbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/pollbot.py)
This example sheds some light on polls, poll answers and the corresponding handlers.
### [`passportbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/passportbot.py)
A basic example of a bot that can accept passports. Use in combination with [`passportbot.html`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/passportbot.html). Don't forget to enable and configure payments with [@BotFather](https://telegram.me/BotFather). Check out this [guide](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Telegram-Passport) on Telegram passports in PTB.
### [`paymentbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/paymentbot.py)
A basic example of a bot that can accept payments. Don't forget to enable and configure payments with [@BotFather](https://telegram.me/BotFather).
### [`errorhandlerbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/errorhandlerbot.py)
A basic example on how to set up a custom error handler.
### [`chatmemberbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/chatmemberbot.py)
A basic example on how `(my_)chat_member` updates can be used.
### [`contexttypesbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/contexttypesbot.py)
This example showcases how `telegram.ext.ContextTypes` can be used to customize the `context` argument of handler and job callbacks.
### [`arbitrarycallbackdatabot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/arbitrarycallbackdatabot.py)
This example showcases how PTBs "arbitrary callback data" feature can be used.
## Pure API
The [`rawapibot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/rawapibot.py) example uses only the pure, "bare-metal" API wrapper.
All examples are licensed under the [CC0 License](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/LICENSE.txt) and are therefore fully dedicated to the public domain. You can use them as the base for your own bots without worrying about copyrights.
+20 -7
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""This example showcases how PTBs "arbitrary callback data" feature can be used.
@@ -10,12 +10,25 @@ https://github.com/python-telegram-bot/python-telegram-bot/wiki/Arbitrary-callba
import logging
from typing import List, Tuple, cast
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import (
Application,
CallbackContext,
CallbackQueryHandler,
CommandHandler,
ContextTypes,
InvalidCallbackData,
PicklePersistence,
)
@@ -27,13 +40,13 @@ logging.basicConfig(
logger = logging.getLogger(__name__)
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Sends a message with 5 inline buttons attached."""
number_list: List[int] = []
await update.message.reply_text("Please choose:", reply_markup=build_keyboard(number_list))
async def help_command(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Displays info on how to use the bot."""
await update.message.reply_text(
"Use /start to test this bot. Use /clear to clear the stored data so that you can see "
@@ -41,7 +54,7 @@ async def help_command(update: Update, context: CallbackContext.DEFAULT_TYPE) ->
)
async def clear(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def clear(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Clears the callback data cache"""
context.bot.callback_data_cache.clear_callback_data()
context.bot.callback_data_cache.clear_callback_queries()
@@ -55,7 +68,7 @@ def build_keyboard(current_list: List[int]) -> InlineKeyboardMarkup:
)
async def list_button(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def list_button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Parses the CallbackQuery and updates the message text."""
query = update.callback_query
await query.answer()
@@ -75,7 +88,7 @@ async def list_button(update: Update, context: CallbackContext.DEFAULT_TYPE) ->
context.drop_callback_data(query)
async def handle_invalid_button(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def handle_invalid_button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Informs the user that the button is no longer available."""
await update.callback_query.answer()
await update.effective_message.edit_text(
+19 -8
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -14,9 +14,22 @@ bot.
import logging
from typing import Optional, Tuple
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import Chat, ChatMember, ChatMemberUpdated, Update
from telegram.constants import ParseMode
from telegram.ext import Application, CallbackContext, ChatMemberHandler, CommandHandler
from telegram.ext import Application, ChatMemberHandler, CommandHandler, ContextTypes
# Enable logging
@@ -27,9 +40,7 @@ logging.basicConfig(
logger = logging.getLogger(__name__)
def extract_status_change(
chat_member_update: ChatMemberUpdated,
) -> Optional[Tuple[bool, bool]]:
def extract_status_change(chat_member_update: ChatMemberUpdated) -> Optional[Tuple[bool, bool]]:
"""Takes a ChatMemberUpdated instance and extracts whether the 'old_chat_member' was a member
of the chat and whether the 'new_chat_member' is a member of the chat. Returns None, if
the status didn't change.
@@ -55,7 +66,7 @@ def extract_status_change(
return was_member, is_member
async def track_chats(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def track_chats(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Tracks the chats the bot is in."""
result = extract_status_change(update.my_chat_member)
if result is None:
@@ -90,7 +101,7 @@ async def track_chats(update: Update, context: CallbackContext.DEFAULT_TYPE) ->
context.bot_data.setdefault("channel_ids", set()).discard(chat.id)
async def show_chats(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def show_chats(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Shows which chats the bot is in"""
user_ids = ", ".join(str(uid) for uid in context.bot_data.setdefault("user_ids", set()))
group_ids = ", ".join(str(gid) for gid in context.bot_data.setdefault("group_ids", set()))
@@ -103,7 +114,7 @@ async def show_chats(update: Update, context: CallbackContext.DEFAULT_TYPE) -> N
await update.effective_message.reply_text(text)
async def greet_chat_members(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def greet_chat_members(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Greets new users in chats and announces when someone leaves"""
result = extract_status_change(update.chat_member)
if result is None:
+16 -3
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -14,6 +14,19 @@ import logging
from collections import defaultdict
from typing import DefaultDict, Optional, Set
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.constants import ParseMode
from telegram.ext import (
@@ -44,8 +57,8 @@ class ChatData:
class CustomContext(CallbackContext[ExtBot, dict, ChatData, dict]):
"""Custom class for context."""
def __init__(self, application: Application):
super().__init__(application=application)
def __init__(self, application: Application, chat_id: int = None, user_id: int = None):
super().__init__(application=application, chat_id=chat_id, user_id=user_id)
self._message_id: Optional[int] = None
@property
+21
View File
@@ -0,0 +1,21 @@
flowchart TB
%% Documentation: https://mermaid-js.github.io/mermaid/#/flowchart
A(("/start")):::entryPoint -->|Hi! My name is Professor Bot...| B((GENDER)):::state
B --> |"- Boy <br /> - Girl <br /> - Other"|C("(choice)"):::userInput
C --> |I see! Please send me a photo...| D((PHOTO)):::state
D --> E("/skip"):::userInput
D --> F("(photo)"):::userInput
E --> |I bet you look great!| G[\ /]:::userInput
F --> |Gorgeous!| G[\ /]
G --> |"Now, send me your location .."| H((LOCATION)):::state
H --> I("/skip"):::userInput
H --> J("(location)"):::userInput
I --> |You seem a bit paranoid!| K[\" "/]:::userInput
J --> |Maybe I can visit...| K
K --> |"Tell me about yourself..."| L(("BIO")):::state
L --> M("(text)"):::userInput
M --> |"Thanks and bye!"| End(("END")):::termination
classDef userInput fill:#2a5279, color:#ffffff, stroke:#ffffff
classDef state fill:#222222, color:#ffffff, stroke:#ffffff
classDef entryPoint fill:#009c11, stroke:#42FF57, color:#ffffff
classDef termination fill:#bb0007, stroke:#E60109, color:#ffffff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

+23 -10
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -16,11 +16,24 @@ bot.
import logging
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update
from telegram.ext import (
Application,
CallbackContext,
CommandHandler,
ContextTypes,
ConversationHandler,
MessageHandler,
filters,
@@ -35,7 +48,7 @@ logger = logging.getLogger(__name__)
GENDER, PHOTO, LOCATION, BIO = range(4)
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Starts the conversation and asks the user about their gender."""
reply_keyboard = [["Boy", "Girl", "Other"]]
@@ -51,7 +64,7 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
return GENDER
async def gender(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def gender(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Stores the selected gender and asks for a photo."""
user = update.message.from_user
logger.info("Gender of %s: %s", user.first_name, update.message.text)
@@ -64,7 +77,7 @@ async def gender(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
return PHOTO
async def photo(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def photo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Stores the photo and asks for a location."""
user = update.message.from_user
photo_file = await update.message.photo[-1].get_file()
@@ -77,7 +90,7 @@ async def photo(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
return LOCATION
async def skip_photo(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def skip_photo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Skips the photo and asks for a location."""
user = update.message.from_user
logger.info("User %s did not send a photo.", user.first_name)
@@ -88,7 +101,7 @@ async def skip_photo(update: Update, context: CallbackContext.DEFAULT_TYPE) -> i
return LOCATION
async def location(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def location(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Stores the location and asks for some info about the user."""
user = update.message.from_user
user_location = update.message.location
@@ -102,7 +115,7 @@ async def location(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int
return BIO
async def skip_location(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def skip_location(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Skips the location and asks for info about the user."""
user = update.message.from_user
logger.info("User %s did not send a location.", user.first_name)
@@ -113,7 +126,7 @@ async def skip_location(update: Update, context: CallbackContext.DEFAULT_TYPE) -
return BIO
async def bio(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def bio(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Stores the info about the user and ends the conversation."""
user = update.message.from_user
logger.info("Bio of %s: %s", user.first_name, update.message.text)
@@ -122,7 +135,7 @@ async def bio(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
return ConversationHandler.END
async def cancel(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Cancels and ends the conversation."""
user = update.message.from_user
logger.info("User %s canceled the conversation.", user.first_name)
+17
View File
@@ -0,0 +1,17 @@
flowchart TB
%% Documentation: https://mermaid-js.github.io/mermaid/#/flowchart
A(("/start")):::entryPoint -->|Hi! My name is Doctor Botter...| B((CHOOSING)):::state
B --> C("Something else..."):::userInput
C --> |What category?| D((TYPING_CHOICE)):::state
D --> E("(text)"):::userInput
E --> |"[save choice] <br /> I'd love to hear about that!"| F((TYPING_REPLY)):::state
F --> G("(text)"):::userInput
G --> |"[save choice: text] <br /> Neat! <br /> (List of facts) <br /> More?"| B
B --> H("- Age <br /> - Favourite colour <br /> - Number of siblings"):::userInput
H --> |"[save choice] <br /> I'd love to hear about that!"| F
B --> I("Done"):::userInput
I --> |"I learned these facts about you: <br /> ..."| End(("END")):::termination
classDef userInput fill:#2a5279, color:#ffffff, stroke:#ffffff
classDef state fill:#222222, color:#ffffff, stroke:#ffffff
classDef entryPoint fill:#009c11, stroke:#42FF57, color:#ffffff
classDef termination fill:#bb0007, stroke:#E60109, color:#ffffff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

+20 -7
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -17,11 +17,24 @@ bot.
import logging
from typing import Dict
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update
from telegram.ext import (
Application,
CallbackContext,
CommandHandler,
ContextTypes,
ConversationHandler,
MessageHandler,
filters,
@@ -49,7 +62,7 @@ def facts_to_str(user_data: Dict[str, str]) -> str:
return "\n".join(facts).join(["\n", "\n"])
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Start the conversation and ask user for input."""
await update.message.reply_text(
"Hi! My name is Doctor Botter. I will hold a more complex conversation with you. "
@@ -60,7 +73,7 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
return CHOOSING
async def regular_choice(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def regular_choice(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Ask the user for info about the selected predefined choice."""
text = update.message.text
context.user_data["choice"] = text
@@ -69,7 +82,7 @@ async def regular_choice(update: Update, context: CallbackContext.DEFAULT_TYPE)
return TYPING_REPLY
async def custom_choice(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def custom_choice(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Ask the user for a description of a custom category."""
await update.message.reply_text(
'Alright, please send me the category first, for example "Most impressive skill"'
@@ -78,7 +91,7 @@ async def custom_choice(update: Update, context: CallbackContext.DEFAULT_TYPE) -
return TYPING_CHOICE
async def received_information(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def received_information(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Store info provided by user and ask for the next category."""
user_data = context.user_data
text = update.message.text
@@ -96,7 +109,7 @@ async def received_information(update: Update, context: CallbackContext.DEFAULT_
return CHOOSING
async def done(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def done(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Display the gathered info and end the conversation."""
user_data = context.user_data
if "choice" in user_data:
+192
View File
@@ -0,0 +1,192 @@
#!/usr/bin/env python
# This program is dedicated to the public domain under the CC0 license.
# pylint: disable=import-error,wrong-import-position
"""
Simple example of a bot that uses a custom webhook setup and handles custom updates.
For the custom webhook setup, the libraries `starlette` and `uvicorn` are used. Please install
them as `pip install starlette~=0.20.0 uvicorn~=0.17.0`.
Note that any other `asyncio` based web server framework can be used for a custom webhook setup
just as well.
Usage:
Set bot token, url, admin chat_id and port at the start of the `main` function.
You may also need to change the `listen` value in the uvicorn configuration to match your setup.
Press Ctrl-C on the command line or send a signal to the process to stop the bot.
"""
import asyncio
import html
import logging
from dataclasses import dataclass
from http import HTTPStatus
import uvicorn
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import PlainTextResponse, Response
from starlette.routing import Route
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import Update
from telegram.constants import ParseMode
from telegram.ext import (
Application,
CallbackContext,
CommandHandler,
ContextTypes,
ExtBot,
TypeHandler,
)
# Enable logging
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
)
logger = logging.getLogger(__name__)
@dataclass
class WebhookUpdate:
"""Simple dataclass to wrap a custom update type"""
user_id: int
payload: str
class CustomContext(CallbackContext[ExtBot, dict, dict, dict]):
"""
Custom CallbackContext class that makes `user_data` available for updates of type
`WebhookUpdate`.
"""
@classmethod
def from_update(
cls,
update: object,
application: "Application",
) -> "CustomContext":
if isinstance(update, WebhookUpdate):
return cls(application=application, user_id=update.user_id)
return super().from_update(update, application)
async def start(update: Update, context: CustomContext) -> None:
"""Display a message with instructions on how to use this bot."""
url = context.bot_data["url"]
payload_url = html.escape(f"{url}/submitpayload?user_id=<your user id>&payload=<payload>")
text = (
f"To check if the bot is still running, call <code>{url}/healthcheck</code>.\n\n"
f"To post a custom update, call <code>{payload_url}</code>."
)
await update.message.reply_html(text=text)
async def webhook_update(update: WebhookUpdate, context: CustomContext) -> None:
"""Callback that handles the custom updates."""
chat_member = await context.bot.get_chat_member(chat_id=update.user_id, user_id=update.user_id)
payloads = context.user_data.setdefault("payloads", [])
payloads.append(update.payload)
combined_payloads = "</code>\n• <code>".join(payloads)
text = (
f"The user {chat_member.user.mention_html()} has sent a new payload. "
f"So far they have sent the following payloads: \n\n• <code>{combined_payloads}</code>"
)
await context.bot.send_message(
chat_id=context.bot_data["admin_chat_id"], text=text, parse_mode=ParseMode.HTML
)
async def main() -> None:
"""Set up the application and a custom webserver."""
url = "https://domain.tld"
admin_chat_id = 123456
port = 8000
context_types = ContextTypes(context=CustomContext)
# Here we set updater to None because we want our custom webhook server to handle the updates
# and hence we don't need an Updater instance
application = (
Application.builder().token("TOKEN").updater(None).context_types(context_types).build()
)
# save the values in `bot_data` such that we may easily access them in the callbacks
application.bot_data["url"] = url
application.bot_data["admin_chat_id"] = admin_chat_id
# register handlers
application.add_handler(CommandHandler("start", start))
application.add_handler(TypeHandler(type=WebhookUpdate, callback=webhook_update))
# Pass webhook settings to telegram
await application.bot.set_webhook(url=f"{url}/telegram")
# Set up webserver
async def telegram(request: Request) -> Response:
"""Handle incoming Telegram updates by putting them into the `update_queue`"""
await application.update_queue.put(
Update.de_json(data=await request.json(), bot=application.bot)
)
return Response()
async def custom_updates(request: Request) -> PlainTextResponse:
"""
Handle incoming webhook updates by also putting them into the `update_queue` if
the required parameters were passed correctly.
"""
try:
user_id = int(request.query_params["user_id"])
payload = request.query_params["payload"]
except KeyError:
return PlainTextResponse(
status_code=HTTPStatus.BAD_REQUEST,
content="Please pass both `user_id` and `payload` as query parameters.",
)
except ValueError:
return PlainTextResponse(
status_code=HTTPStatus.BAD_REQUEST,
content="The `user_id` must be a string!",
)
await application.update_queue.put(WebhookUpdate(user_id=user_id, payload=payload))
return PlainTextResponse("Thank you for the submission! It's being forwarded.")
async def health(_: Request) -> PlainTextResponse:
"""For the health endpoint, reply with a simple plain text message."""
return PlainTextResponse(content="The bot is still running fine :)")
starlette_app = Starlette(
routes=[
Route("/telegram", telegram, methods=["POST"]),
Route("/healthcheck", health, methods=["GET"]),
Route("/submitpayload", custom_updates, methods=["POST", "GET"]),
]
)
webserver = uvicorn.Server(
config=uvicorn.Config(
app=starlette_app,
port=port,
use_colors=False,
host="127.0.0.1",
)
)
# Run application and webserver together
async with application:
await application.start()
await webserver.serve()
await application.stop()
if __name__ == "__main__":
asyncio.run(main())
+21 -16
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""Bot that explains Telegram's "Deep Linking Parameters" functionality.
@@ -20,15 +20,22 @@ bot.
import logging
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, helpers
from telegram.constants import ParseMode
from telegram.ext import (
Application,
CallbackContext,
CallbackQueryHandler,
CommandHandler,
filters,
)
from telegram.ext import Application, CallbackQueryHandler, CommandHandler, ContextTypes, filters
# Enable logging
logging.basicConfig(
@@ -47,7 +54,7 @@ SO_COOL = "so-cool"
KEYBOARD_CALLBACKDATA = "keyboard-callback-data"
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Send a deep-linked URL when the command /start is issued."""
bot = context.bot
url = helpers.create_deep_linked_url(bot.username, CHECK_THIS_OUT, group=True)
@@ -55,7 +62,7 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
await update.message.reply_text(text)
async def deep_linked_level_1(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def deep_linked_level_1(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Reached through the CHECK_THIS_OUT payload"""
bot = context.bot
url = helpers.create_deep_linked_url(bot.username, SO_COOL)
@@ -69,7 +76,7 @@ async def deep_linked_level_1(update: Update, context: CallbackContext.DEFAULT_T
await update.message.reply_text(text, reply_markup=keyboard)
async def deep_linked_level_2(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def deep_linked_level_2(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Reached through the SO_COOL payload"""
bot = context.bot
url = helpers.create_deep_linked_url(bot.username, USING_ENTITIES)
@@ -77,7 +84,7 @@ async def deep_linked_level_2(update: Update, context: CallbackContext.DEFAULT_T
await update.message.reply_text(text, parse_mode=ParseMode.HTML, disable_web_page_preview=True)
async def deep_linked_level_3(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def deep_linked_level_3(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Reached through the USING_ENTITIES payload"""
await update.message.reply_text(
"It is also possible to make deep-linking using InlineKeyboardButtons.",
@@ -87,16 +94,14 @@ async def deep_linked_level_3(update: Update, context: CallbackContext.DEFAULT_T
)
async def deep_link_level_3_callback(
update: Update, context: CallbackContext.DEFAULT_TYPE
) -> None:
async def deep_link_level_3_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Answers CallbackQuery with deeplinking url."""
bot = context.bot
url = helpers.create_deep_linked_url(bot.username, USING_KEYBOARD)
await update.callback_query.answer(url=url)
async def deep_linked_level_4(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def deep_linked_level_4(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Reached through the USING_KEYBOARD payload"""
payload = context.args
await update.message.reply_text(
+18 -5
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -17,8 +17,21 @@ bot.
import logging
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import ForceReply, Update
from telegram.ext import Application, CallbackContext, CommandHandler, MessageHandler, filters
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
# Enable logging
logging.basicConfig(
@@ -29,7 +42,7 @@ logger = logging.getLogger(__name__)
# Define a few command handlers. These usually take the two arguments update and
# context.
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Send a message when the command /start is issued."""
user = update.effective_user
await update.message.reply_html(
@@ -38,12 +51,12 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
)
async def help_command(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Send a message when the command /help is issued."""
await update.message.reply_text("Help!")
async def echo(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Echo the user message."""
await update.message.reply_text(update.message.text)
+18 -5
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""This is a very simple example on how one could implement a custom error handler."""
@@ -8,9 +8,22 @@ import json
import logging
import traceback
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import Update
from telegram.constants import ParseMode
from telegram.ext import Application, CallbackContext, CommandHandler
from telegram.ext import Application, CommandHandler, ContextTypes
# Enable logging
logging.basicConfig(
@@ -23,7 +36,7 @@ logger = logging.getLogger(__name__)
DEVELOPER_CHAT_ID = 123456789
async def error_handler(update: object, context: CallbackContext.DEFAULT_TYPE) -> None:
async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Log the error and send a telegram message to notify the developer."""
# Log the error before we do anything else, so we can see it even if something breaks.
logger.error(msg="Exception while handling an update:", exc_info=context.error)
@@ -51,12 +64,12 @@ async def error_handler(update: object, context: CallbackContext.DEFAULT_TYPE) -
)
async def bad_command(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def bad_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Raise an error to trigger the error handler."""
await context.bot.wrong_method_name() # type: ignore[attr-defined]
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Displays info on how to trigger an error."""
await update.effective_message.reply_html(
"Use /bad_command to cause an error.\n"
+20 -5
View File
@@ -1,8 +1,10 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
Don't forget to enable inline mode with @BotFather
First, a few handler functions are defined. Then, those functions are passed to
the Application and registered at their respective places.
Then, the bot is started and runs until we press Ctrl-C on the command line.
@@ -16,9 +18,22 @@ import logging
from html import escape
from uuid import uuid4
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import InlineQueryResultArticle, InputTextMessageContent, Update
from telegram.constants import ParseMode
from telegram.ext import Application, CallbackContext, CommandHandler, InlineQueryHandler
from telegram.ext import Application, CommandHandler, ContextTypes, InlineQueryHandler
# Enable logging
logging.basicConfig(
@@ -29,17 +44,17 @@ logger = logging.getLogger(__name__)
# Define a few command handlers. These usually take the two arguments update and
# context.
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Send a message when the command /start is issued."""
await update.message.reply_text("Hi!")
async def help_command(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Send a message when the command /help is issued."""
await update.message.reply_text("Help!")
async def inline_query(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def inline_query(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Handle the inline query. This is run when you type: @botusername <query>"""
query = update.inline_query.query
+18 -5
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -8,8 +8,21 @@ Basic example for a bot that uses inline keyboards. For an in-depth explanation,
"""
import logging
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import Application, CallbackContext, CallbackQueryHandler, CommandHandler
from telegram.ext import Application, CallbackQueryHandler, CommandHandler, ContextTypes
# Enable logging
logging.basicConfig(
@@ -18,7 +31,7 @@ logging.basicConfig(
logger = logging.getLogger(__name__)
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Sends a message with three inline buttons attached."""
keyboard = [
[
@@ -33,7 +46,7 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
await update.message.reply_text("Please choose:", reply_markup=reply_markup)
async def button(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Parses the CallbackQuery and updates the message text."""
query = update.callback_query
@@ -44,7 +57,7 @@ async def button(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
await query.edit_message_text(text=f"Selected option: {query.data}")
async def help_command(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Displays info on how to use the bot."""
await update.message.reply_text("Use /start to test this bot.")
+22 -9
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""Simple inline keyboard bot with multiple CallbackQueryHandlers.
@@ -16,12 +16,25 @@ Press Ctrl-C on the command line to stop the bot.
"""
import logging
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import (
Application,
CallbackContext,
CallbackQueryHandler,
CommandHandler,
ContextTypes,
ConversationHandler,
)
@@ -37,7 +50,7 @@ START_ROUTES, END_ROUTES = range(2)
ONE, TWO, THREE, FOUR = range(4)
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Send message on `/start`."""
# Get user that sent /start and log his name
user = update.message.from_user
@@ -59,7 +72,7 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
return START_ROUTES
async def start_over(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def start_over(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Prompt same text & keyboard as `start` does but not as new message"""
# Get CallbackQuery from Update
query = update.callback_query
@@ -80,7 +93,7 @@ async def start_over(update: Update, context: CallbackContext.DEFAULT_TYPE) -> i
return START_ROUTES
async def one(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def one(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Show new choice of buttons"""
query = update.callback_query
await query.answer()
@@ -97,7 +110,7 @@ async def one(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
return START_ROUTES
async def two(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def two(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Show new choice of buttons"""
query = update.callback_query
await query.answer()
@@ -114,7 +127,7 @@ async def two(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
return START_ROUTES
async def three(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def three(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Show new choice of buttons. This is the end point of the conversation."""
query = update.callback_query
await query.answer()
@@ -132,7 +145,7 @@ async def three(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
return END_ROUTES
async def four(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def four(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Show new choice of buttons"""
query = update.callback_query
await query.answer()
@@ -149,7 +162,7 @@ async def four(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
return START_ROUTES
async def end(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def end(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Returns `ConversationHandler.END`, which tells the
ConversationHandler that the conversation is over.
"""
+43
View File
@@ -0,0 +1,43 @@
flowchart TB
%% Documentation: https://mermaid-js.github.io/mermaid/#/flowchart
A(("/start")):::entryPoint -->|Hi! I'm FamilyBot...| B((SELECTING_ACTION)):::state
B --> C("Show Data"):::userInput
C --> |"(List of gathered data)"| D((SHOWING)):::state
D --> E("Back"):::userInput
E --> B
B --> F("Add Yourself"):::userInput
F --> G(("DESCRIBING_SELF")):::state
G --> H("Add info"):::userInput
H --> I((SELECT_FEATURE)):::state
I --> |"Please select a feature to update. <br /> - Name <br /> - Age <br /> - Done"|J("(choice)"):::userInput
J --> |"Okay, tell me."| K((TYPING)):::state
K --> L("(text)"):::userInput
L --> |"[saving]"|I
I --> M("Done"):::userInput
M --> B
B --> N("Add family member"):::userInput
R --> I
W --> |"See you around!"|End(("END")):::termination
Y(("ANY STATE")):::state --> Z("/stop"):::userInput
Z -->|"Okay, bye."| End
B --> W("Done"):::userInput
subgraph nestedConversation[Nested Conversation: Add Family Member]
direction BT
N --> O(("SELECT_LEVEL")):::state
O --> |"Add... <br /> - Add Parent <br /> - Add Child <br />"|P("(choice)"):::userInput
P --> Q(("SELECT_GENDER")):::state
Q --> |"- Mother <br /> - Father <br /> / <br /> - Sister <br /> - Brother"| R("(choice)"):::userInput
Q --> V("Show Data"):::userInput
Q --> T(("SELECTING_ACTION")):::state
Q --> U("Back"):::userInput
U --> T
O --> U
O --> V
V --> S(("SHOWING")):::state
V --> T
end
classDef userInput fill:#2a5279, color:#ffffff, stroke:#ffffff
classDef state fill:#222222, color:#ffffff, stroke:#ffffff
classDef entryPoint fill:#009c11, stroke:#42FF57, color:#ffffff
classDef termination fill:#bb0007, stroke:#E60109, color:#ffffff
style nestedConversation fill:#999999, stroke-width:2px, stroke:#333333
Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 KiB

+28 -15
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -17,12 +17,25 @@ bot.
import logging
from typing import Any, Dict, Tuple
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import (
Application,
CallbackContext,
CallbackQueryHandler,
CommandHandler,
ContextTypes,
ConversationHandler,
MessageHandler,
filters,
@@ -70,7 +83,7 @@ def _name_switcher(level: str) -> Tuple[str, str]:
# Top level conversation callbacks
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> str:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
"""Select an action: Adding parent/child or show data."""
text = (
"You may choose to add a family member, yourself, show the gathered data, or end the "
@@ -103,7 +116,7 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> str:
return SELECTING_ACTION
async def adding_self(update: Update, context: CallbackContext.DEFAULT_TYPE) -> str:
async def adding_self(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
"""Add information about yourself."""
context.user_data[CURRENT_LEVEL] = SELF
text = "Okay, please tell me about yourself."
@@ -116,7 +129,7 @@ async def adding_self(update: Update, context: CallbackContext.DEFAULT_TYPE) ->
return DESCRIBING_SELF
async def show_data(update: Update, context: CallbackContext.DEFAULT_TYPE) -> str:
async def show_data(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
"""Pretty print gathered data."""
def pretty_print(data: Dict[str, Any], level: str) -> str:
@@ -153,14 +166,14 @@ async def show_data(update: Update, context: CallbackContext.DEFAULT_TYPE) -> st
return SHOWING
async def stop(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def stop(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""End Conversation by command."""
await update.message.reply_text("Okay, bye.")
return END
async def end(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def end(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""End conversation from InlineKeyboardButton."""
await update.callback_query.answer()
@@ -171,7 +184,7 @@ async def end(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
# Second level conversation callbacks
async def select_level(update: Update, context: CallbackContext.DEFAULT_TYPE) -> str:
async def select_level(update: Update, context: ContextTypes.DEFAULT_TYPE) -> 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 = [
@@ -192,7 +205,7 @@ async def select_level(update: Update, context: CallbackContext.DEFAULT_TYPE) ->
return SELECTING_LEVEL
async def select_gender(update: Update, context: CallbackContext.DEFAULT_TYPE) -> str:
async def select_gender(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
"""Choose to add mother or father."""
level = update.callback_query.data
context.user_data[CURRENT_LEVEL] = level
@@ -219,7 +232,7 @@ async def select_gender(update: Update, context: CallbackContext.DEFAULT_TYPE) -
return SELECTING_GENDER
async def end_second_level(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def end_second_level(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Return to top level conversation."""
context.user_data[START_OVER] = True
await start(update, context)
@@ -228,7 +241,7 @@ async def end_second_level(update: Update, context: CallbackContext.DEFAULT_TYPE
# Third level callbacks
async def select_feature(update: Update, context: CallbackContext.DEFAULT_TYPE) -> str:
async def select_feature(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
"""Select a feature to update for the person."""
buttons = [
[
@@ -255,7 +268,7 @@ async def select_feature(update: Update, context: CallbackContext.DEFAULT_TYPE)
return SELECTING_FEATURE
async def ask_for_input(update: Update, context: CallbackContext.DEFAULT_TYPE) -> str:
async def ask_for_input(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
"""Prompt user to input data for selected feature."""
context.user_data[CURRENT_FEATURE] = update.callback_query.data
text = "Okay, tell me."
@@ -266,7 +279,7 @@ async def ask_for_input(update: Update, context: CallbackContext.DEFAULT_TYPE) -
return TYPING
async def save_input(update: Update, context: CallbackContext.DEFAULT_TYPE) -> str:
async def save_input(update: Update, context: ContextTypes.DEFAULT_TYPE) -> 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
@@ -276,7 +289,7 @@ async def save_input(update: Update, context: CallbackContext.DEFAULT_TYPE) -> s
return await select_feature(update, context)
async def end_describing(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def end_describing(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""End gathering of features and return to parent conversation."""
user_data = context.user_data
level = user_data[CURRENT_LEVEL]
@@ -294,7 +307,7 @@ async def end_describing(update: Update, context: CallbackContext.DEFAULT_TYPE)
return END
async def stop_nested(update: Update, context: CallbackContext.DEFAULT_TYPE) -> str:
async def stop_nested(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
"""Completely end conversation from within nested conversation."""
await update.message.reply_text("Okay, bye.")
+16 -3
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -14,8 +14,21 @@ See https://github.com/python-telegram-bot/python-telegram-bot/wiki/Telegram-Pas
import logging
from pathlib import Path
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import Update
from telegram.ext import Application, CallbackContext, MessageHandler, filters
from telegram.ext import Application, ContextTypes, MessageHandler, filters
# Enable logging
@@ -26,7 +39,7 @@ logging.basicConfig(
logger = logging.getLogger(__name__)
async def msg(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Downloads and prints the received passport data."""
# Retrieve passport data
passport_data = update.message.passport_data
+21 -12
View File
@@ -1,16 +1,29 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""Basic example for a bot that can receive payment from user."""
import logging
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import LabeledPrice, ShippingOption, Update
from telegram.ext import (
Application,
CallbackContext,
CommandHandler,
ContextTypes,
MessageHandler,
PreCheckoutQueryHandler,
ShippingQueryHandler,
@@ -26,7 +39,7 @@ logger = logging.getLogger(__name__)
PAYMENT_PROVIDER_TOKEN = "PAYMENT_PROVIDER_TOKEN"
async def start_callback(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def start_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Displays info on how to use the bot."""
msg = (
"Use /shipping to get an invoice for shipping-payment, or /noshipping for an "
@@ -36,9 +49,7 @@ async def start_callback(update: Update, context: CallbackContext.DEFAULT_TYPE)
await update.message.reply_text(msg)
async def start_with_shipping_callback(
update: Update, context: CallbackContext.DEFAULT_TYPE
) -> None:
async def start_with_shipping_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Sends an invoice with shipping-payment."""
chat_id = update.message.chat_id
title = "Payment Example"
@@ -72,7 +83,7 @@ async def start_with_shipping_callback(
async def start_without_shipping_callback(
update: Update, context: CallbackContext.DEFAULT_TYPE
update: Update, context: ContextTypes.DEFAULT_TYPE
) -> None:
"""Sends an invoice without shipping-payment."""
chat_id = update.message.chat_id
@@ -94,7 +105,7 @@ async def start_without_shipping_callback(
)
async def shipping_callback(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def shipping_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Answers the ShippingQuery with ShippingOptions"""
query = update.shipping_query
# check the payload, is this from your bot?
@@ -112,7 +123,7 @@ async def shipping_callback(update: Update, context: CallbackContext.DEFAULT_TYP
# after (optional) shipping, it's the pre-checkout
async def precheckout_callback(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def precheckout_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Answers the PreQecheckoutQuery"""
query = update.pre_checkout_query
# check the payload, is this from your bot?
@@ -124,9 +135,7 @@ async def precheckout_callback(update: Update, context: CallbackContext.DEFAULT_
# finally, after contacting the payment provider...
async def successful_payment_callback(
update: Update, context: CallbackContext.DEFAULT_TYPE
) -> None:
async def successful_payment_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Confirms the successful payment."""
# do something after successfully receiving payment?
await update.message.reply_text("Thank you for your payment!")
+21 -8
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -17,11 +17,24 @@ bot.
import logging
from typing import Dict
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update
from telegram.ext import (
Application,
CallbackContext,
CommandHandler,
ContextTypes,
ConversationHandler,
MessageHandler,
PicklePersistence,
@@ -50,7 +63,7 @@ def facts_to_str(user_data: Dict[str, str]) -> str:
return "\n".join(facts).join(["\n", "\n"])
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Start the conversation, display any stored data and ask user for input."""
reply_text = "Hi! My name is Doctor Botter."
if context.user_data:
@@ -68,7 +81,7 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
return CHOOSING
async def regular_choice(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def regular_choice(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Ask the user for info about the selected predefined choice."""
text = update.message.text.lower()
context.user_data["choice"] = text
@@ -83,7 +96,7 @@ async def regular_choice(update: Update, context: CallbackContext.DEFAULT_TYPE)
return TYPING_REPLY
async def custom_choice(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def custom_choice(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Ask the user for a description of a custom category."""
await update.message.reply_text(
'Alright, please send me the category first, for example "Most impressive skill"'
@@ -92,7 +105,7 @@ async def custom_choice(update: Update, context: CallbackContext.DEFAULT_TYPE) -
return TYPING_CHOICE
async def received_information(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def received_information(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Store info provided by user and ask for the next category."""
text = update.message.text
category = context.user_data["choice"]
@@ -109,14 +122,14 @@ async def received_information(update: Update, context: CallbackContext.DEFAULT_
return CHOOSING
async def show_data(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def show_data(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Display the gathered info."""
await update.message.reply_text(
f"This is what you already told me: {facts_to_str(context.user_data)}"
)
async def done(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int:
async def done(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
"""Display the gathered info and end the conversation."""
if "choice" in context.user_data:
del context.user_data["choice"]
+23 -10
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -9,6 +9,19 @@ one the user sends the bot
"""
import logging
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import (
KeyboardButton,
KeyboardButtonPollType,
@@ -20,8 +33,8 @@ from telegram import (
from telegram.constants import ParseMode
from telegram.ext import (
Application,
CallbackContext,
CommandHandler,
ContextTypes,
MessageHandler,
PollAnswerHandler,
PollHandler,
@@ -35,7 +48,7 @@ logging.basicConfig(
logger = logging.getLogger(__name__)
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Inform user about what this bot can do"""
await update.message.reply_text(
"Please select /poll to get a Poll, /quiz to get a Quiz or /preview"
@@ -43,7 +56,7 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
)
async def poll(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def poll(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Sends a predefined poll"""
questions = ["Good", "Really good", "Fantastic", "Great"]
message = await context.bot.send_poll(
@@ -65,7 +78,7 @@ async def poll(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
context.bot_data.update(payload)
async def receive_poll_answer(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def receive_poll_answer(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Summarize a users poll vote"""
answer = update.poll_answer
answered_poll = context.bot_data[answer.poll_id]
@@ -92,7 +105,7 @@ async def receive_poll_answer(update: Update, context: CallbackContext.DEFAULT_T
await context.bot.stop_poll(answered_poll["chat_id"], answered_poll["message_id"])
async def quiz(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def quiz(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Send a predefined poll"""
questions = ["1", "2", "4", "20"]
message = await update.effective_message.reply_poll(
@@ -105,7 +118,7 @@ async def quiz(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
context.bot_data.update(payload)
async def receive_quiz_answer(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def receive_quiz_answer(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Close quiz after three participants took it"""
# the bot can receive closed poll updates we don't care about
if update.poll.is_closed:
@@ -119,7 +132,7 @@ async def receive_quiz_answer(update: Update, context: CallbackContext.DEFAULT_T
await context.bot.stop_poll(quiz_data["chat_id"], quiz_data["message_id"])
async def preview(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def preview(update: Update, context: ContextTypes.DEFAULT_TYPE) -> 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())]]
@@ -130,7 +143,7 @@ async def preview(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None
)
async def receive_poll(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def receive_poll(update: Update, context: ContextTypes.DEFAULT_TYPE) -> 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
@@ -144,7 +157,7 @@ async def receive_poll(update: Update, context: CallbackContext.DEFAULT_TYPE) ->
)
async def help_handler(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def help_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Display a help message"""
await update.message.reply_text("Use /quiz, /poll or /preview to test this bot.")
+14
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python
# pylint: disable=wrong-import-position
"""Simple Bot to reply to Telegram messages.
This is built on the API wrapper, see echobot.py to see the same example built
@@ -9,6 +10,19 @@ import asyncio
import logging
from typing import NoReturn
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment] # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import Bot
from telegram.error import Forbidden, NetworkError
+25 -12
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# pylint: disable=unused-argument
# pylint: disable=unused-argument, wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
@@ -20,8 +20,21 @@ bot.
import logging
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import Update
from telegram.ext import Application, CallbackContext, CommandHandler
from telegram.ext import Application, CommandHandler, ContextTypes
# Enable logging
logging.basicConfig(
@@ -35,18 +48,18 @@ logging.basicConfig(
# since context is an unused local variable.
# This being an example and not having context present confusing beginners,
# we decided to have it present as context.
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Sends explanation on how to use the bot."""
await update.message.reply_text("Hi! Use /set <seconds> to set a timer")
async def alarm(context: CallbackContext.DEFAULT_TYPE) -> None:
async def alarm(context: ContextTypes.DEFAULT_TYPE) -> None:
"""Send the alarm message."""
job = context.job
await context.bot.send_message(job.chat_id, text=f"Beep! {job.context} seconds are over!")
await context.bot.send_message(job.chat_id, text=f"Beep! {job.data} seconds are over!")
def remove_job_if_exists(name: str, context: CallbackContext.DEFAULT_TYPE) -> bool:
def remove_job_if_exists(name: str, context: ContextTypes.DEFAULT_TYPE) -> 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:
@@ -56,29 +69,29 @@ def remove_job_if_exists(name: str, context: CallbackContext.DEFAULT_TYPE) -> bo
return True
async def set_timer(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def set_timer(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Add a job to the queue."""
chat_id = update.effective_message.chat_id
try:
# args[0] should contain the time for the timer in seconds
due = int(context.args[0])
due = float(context.args[0])
if due < 0:
await update.message.reply_text("Sorry we can not go back to future!")
await update.effective_message.reply_text("Sorry we can not go back to future!")
return
job_removed = remove_job_if_exists(str(chat_id), context)
context.job_queue.run_once(alarm, due, chat_id=chat_id, name=str(chat_id), context=due)
context.job_queue.run_once(alarm, due, chat_id=chat_id, name=str(chat_id), data=due)
text = "Timer successfully set!"
if job_removed:
text += " Old one was removed."
await update.message.reply_text(text)
await update.effective_message.reply_text(text)
except (IndexError, ValueError):
await update.effective_message.reply_text("Usage: /set <seconds>")
async def unset(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
async def unset(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Remove the job if the user changed their mind."""
chat_id = update.message.chat_id
job_removed = remove_job_if_exists(str(chat_id), context)
+39
View File
@@ -0,0 +1,39 @@
<!--
Simple static Telegram WebApp. Does not verify the WebAppInitData, as a bot token would be needed for that.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>python-telegram-bot Example WebApp</title>
<script src="https://telegram.org/js/telegram-web-app.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@jaames/iro@5"></script>
</head>
<script type="text/javascript">
const colorPicker = new iro.ColorPicker('#picker', {
borderColor: "#ffffff",
borderWidth: 1,
width: Math.round(document.documentElement.clientWidth / 2),
});
colorPicker.on('color:change', function (color) {
document.body.style.background = color.hexString;
});
Telegram.WebApp.ready();
Telegram.WebApp.MainButton.setText('Choose Color').show().onClick(function () {
const data = JSON.stringify({hex: colorPicker.color.hexString, rgb: colorPicker.color.rgb});
Telegram.WebApp.sendData(data);
Telegram.WebApp.close();
});
</script>
<body style="background-color: #ffffff">
<div style="position: absolute; margin-top: 5vh; margin-left: 5vw; height: 90vh; width: 90vw; border-radius: 5vh; background-color: var(--tg-theme-bg-color); box-shadow: 0 0 2vw
#000000;">
<div id="picker"
style="display: flex; justify-content: center; align-items: center; height: 100%; width: 100%"></div>
</div>
</body>
<script type="text/javascript">
Telegram.WebApp.expand();
</script>
</html>
+77
View File
@@ -0,0 +1,77 @@
#!/usr/bin/env python
# pylint: disable=unused-argument,wrong-import-position
# This program is dedicated to the public domain under the CC0 license.
"""
Simple example of a Telegram WebApp which displays a color picker.
The static website for this website is hosted by the PTB team for your convenience.
Currently only showcases starting the WebApp via a KeyboardButton, as all other methods would
require a bot token.
"""
import json
import logging
from telegram import __version__ as TG_VER
try:
from telegram import __version_info__
except ImportError:
__version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
if __version_info__ < (20, 0, 0, "alpha", 1):
raise RuntimeError(
f"This example is not compatible with your current PTB version {TG_VER}. To view the "
f"{TG_VER} version of this example, "
f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html"
)
from telegram import KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove, Update, WebAppInfo
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
# Enable logging
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
)
logger = logging.getLogger(__name__)
# Define a `/start` command handler.
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Send a message with a button that opens a the web app."""
await update.message.reply_text(
"Please press the button below to choose a color via the WebApp.",
reply_markup=ReplyKeyboardMarkup.from_button(
KeyboardButton(
text="Open the color picker!",
web_app=WebAppInfo(url="https://python-telegram-bot.org/static/webappbot"),
)
),
)
# Handle incoming WebAppData
async def web_app_data(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Print the received data and remove the button."""
# Here we use `json.loads`, since the WebApp sends the data JSON serialized string
# (see webappbot.html)
data = json.loads(update.effective_message.web_app_data.data)
await update.message.reply_html(
text=f"You selected the color with the HEX value <code>{data['hex']}</code>. The "
f"corresponding RGB value is <code>{tuple(data['rgb'].values())}</code>.",
reply_markup=ReplyKeyboardRemove(),
)
def main() -> None:
"""Start the bot."""
# Create the Application and pass it your bot's token.
application = Application.builder().token("TOKEN").build()
application.add_handler(CommandHandler("start", start))
application.add_handler(MessageHandler(filters.StatusUpdate.WEB_APP_DATA, web_app_data))
# Run the bot until the user presses Ctrl-C
application.run_polling()
if __name__ == "__main__":
main()
+4 -3
View File
@@ -5,13 +5,14 @@ pre-commit
# Make sure that the versions specified here match the pre-commit settings!
black==22.3.0
flake8==4.0.1
pylint==2.13.8
mypy==0.950
pyupgrade==2.32.0
pylint==2.13.9
mypy==0.961
pyupgrade==2.34.0
isort==5.10.1
pytest==7.1.2
pytest-asyncio==0.18.3
pytest-timeout==2.1.0 # used to timeout tests
flaky # Used for flaky tests (flaky decorator)
beautifulsoup4 # used in test_official for parsing tg docs
+2 -2
View File
@@ -6,7 +6,7 @@
# versions and only increase the lower bound if necessary
# httpx has no stable release yet, so let's be cautious for now
httpx ~= 0.22.0
httpx ~= 0.23.0
# only telegram.ext: # Keep this line here; used in setup(-raw).py
# tornado is rather stable, but let's not allow the next mayor release without prior testing
@@ -14,7 +14,7 @@ tornado~=6.1
# Cachetools and APS don't have a strict stability policy.
# Let's be cautious for now.
cachetools~=5.0.0
cachetools~=5.2.0
APScheduler~=3.9.1
# pytz is required by APS and just needs the lower bound due to #2120
+7 -3
View File
@@ -61,9 +61,6 @@ disallow_incomplete_defs = True
disallow_untyped_decorators = True
show_error_codes = True
[mypy-telegram.vendor.*]
ignore_errors = True
# For some files, it's easier to just disable strict-optional all together instead of
# cluttering the code with `# type: ignore`s or stuff like
# `if self.text is None: raise RuntimeError()`
@@ -76,3 +73,10 @@ warn_unused_ignores = False
[mypy-apscheduler.*]
ignore_missing_imports = True
# uvicorn and starlette are only used for the `customwebhookbot.py` example
# let's just ignore type checking for them for now
[mypy-uvicorn.*]
ignore_missing_imports = True
[mypy-starlette.*]
ignore_missing_imports = True
+5 -9
View File
@@ -42,10 +42,9 @@ def get_setup_kwargs(raw=False):
raw_ext = "-raw" if raw else ""
readme = Path(f'README{"_RAW" if raw else ""}.rst')
with Path("telegram/_version.py").open() as fh:
for line in fh.readlines():
if line.startswith("__version__"):
exec(line)
version_file = Path("telegram/_version.py").read_text()
first_part = version_file.split("# SETUP.PY MARKER")[0]
exec(first_part)
kwargs = dict(
script_name=f"setup{raw_ext}.py",
@@ -57,11 +56,11 @@ def get_setup_kwargs(raw=False):
url="https://python-telegram-bot.org/",
# Keywords supported by PyPI can be found at https://github.com/pypa/warehouse/blob/aafc5185e57e67d43487ce4faa95913dd4573e14/warehouse/templates/packaging/detail.html#L20-L58
project_urls={
"Documentation": "https://python-telegram-bot.readthedocs.io",
"Documentation": "https://docs.python-telegram-bot.org",
"Bug Tracker": "https://github.com/python-telegram-bot/python-telegram-bot/issues",
"Source Code": "https://github.com/python-telegram-bot/python-telegram-bot",
"News": "https://t.me/pythontelegrambotchannel",
"Changelog": "https://python-telegram-bot.readthedocs.io/en/stable/changelog.html",
"Changelog": "https://docs.python-telegram-bot.org/en/stable/changelog.html",
},
download_url=f"https://pypi.org/project/python-telegram-bot{raw_ext}/",
keywords="python telegram bot api wrapper",
@@ -72,9 +71,6 @@ def get_setup_kwargs(raw=False):
install_requires=requirements,
extras_require={
"socks": "httpx[socks]",
# json and cryptography are very stable, so we use a reasonably new version as
# lower bound and have no upper bound
"json": "ujson>=4.0.0",
# 3.4-3.4.3 contained some cyclical import bugs
"passport": "cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=3.0",
},
+29 -2
View File
@@ -21,10 +21,13 @@
__author__ = "devs@python-telegram-bot.org"
__all__ = ( # Keep this alphabetically ordered
"__bot_api_version__",
"__bot_api_version_info__",
"__version__",
"__version_info__",
"Animation",
"Audio",
"Bot",
"bot_api_version",
"BotCommand",
"BotCommandScope",
"BotCommandScopeAllChatAdministrators",
@@ -172,6 +175,7 @@ __all__ = ( # Keep this alphabetically ordered
)
from . import _version
from ._bot import Bot
from ._botcommand import BotCommand
from ._botcommandscope import (
@@ -308,7 +312,30 @@ from ._telegramobject import TelegramObject
from ._update import Update
from ._user import User
from ._userprofilephotos import UserProfilePhotos
from ._version import __version__, bot_api_version # noqa: F401
#: :obj:`str`: The version of the `python-telegram-bot` library as string.
#: To get detailed information about the version number, please use :data:`__version_info__`
#: instead.
__version__ = _version.__version__
#: :class:`typing.NamedTuple`: A tuple containing the five components of the version number:
#: `major`, `minor`, `micro`, `releaselevel`, and `serial`.
#: All values except `releaselevel` are integers.
#: The release level is ``'alpha'``, ``'beta'``, ``'candidate'``, or ``'final'``.
#: The components can also be accessed by name, so ``__version_info__[0]`` is equivalent to
#: ``__version_info__.major`` and so on.
#:
#: .. versionadded:: 20.0
__version_info__ = _version.__version_info__
#: :obj:`str`: Shortcut for :const:`telegram.constants.BOT_API_VERSION`.
#:
#: .. versionchanged:: 20.0
#: This constant was previously named ``bot_api_version``.
__bot_api_version__ = _version.__bot_api_version__
#: :class:`typing.NamedTuple`: Shortcut for :const:`telegram.constants.BOT_API_VERSION_INFO`.
#:
#: .. versionadded:: 20.0
__bot_api_version_info__ = _version.__bot_api_version_info__
from ._videochat import (
VideoChatEnded,
VideoChatParticipantsInvited,
+765 -359
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -260,5 +260,5 @@ class BotCommandScopeChatMember(BotCommandScope):
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self.user_id = int(user_id)
self.user_id = user_id
self._id_attrs = (self.type, self.chat_id, self.user_id)
+65 -59
View File
@@ -65,7 +65,6 @@ class CallbackQuery(TelegramObject):
.. versionadded:: 13.6
Args:
id (:obj:`str`): Unique identifier for this query.
from_user (:class:`telegram.User`): Sender.
@@ -74,8 +73,8 @@ class CallbackQuery(TelegramObject):
message (:class:`telegram.Message`, optional): Message with the callback button that
originated the query. Note that message content and message date will not be available
if the message is too old.
data (:obj:`str`, optional): Data associated with the callback button. Be aware that a bad
client can send arbitrary data in this field.
data (:obj:`str`, optional): Data associated with the callback button. Be aware that the
message, which originated the query, can contain no callback buttons with this data.
inline_message_id (:obj:`str`, optional): Identifier of the message sent via the bot in
inline mode, that originated the query.
game_short_name (:obj:`str`, optional): Short name of a Game to be returned, serves as
@@ -90,6 +89,10 @@ class CallbackQuery(TelegramObject):
message (:class:`telegram.Message`): Optional. Message with the callback button that
originated the query.
data (:obj:`str` | :obj:`object`): Optional. Data associated with the callback button.
Tip:
The value here is the same as the value passed in
:paramref:`telegram.InlineKeyboardButton.callback_data`.
inline_message_id (:obj:`str`): Optional. Identifier of the message sent via the bot in
inline mode, that originated the query.
game_short_name (:obj:`str`): Optional. Short name of a Game to be returned.
@@ -149,9 +152,10 @@ class CallbackQuery(TelegramObject):
async def answer(
self,
text: str = None,
show_alert: bool = False,
show_alert: bool = None,
url: str = None,
cache_time: int = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -188,21 +192,23 @@ class CallbackQuery(TelegramObject):
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
reply_markup: "InlineKeyboardMarkup" = None,
entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None,
) -> Union[Message, bool]:
"""Shortcut for either::
update.callback_query.message.edit_text(text, *args, **kwargs)
await update.callback_query.message.edit_text(*args, **kwargs)
or::
bot.edit_message_text(text, inline_message_id=update.callback_query.inline_message_id,
*args, **kwargs)
await bot.edit_message_text(
inline_message_id=update.callback_query.inline_message_id, *args, **kwargs,
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.edit_message_text` and :meth:`telegram.Message.edit_text`.
@@ -245,23 +251,24 @@ class CallbackQuery(TelegramObject):
self,
caption: str = None,
reply_markup: "InlineKeyboardMarkup" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
parse_mode: ODVInput[str] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None,
) -> Union[Message, bool]:
"""Shortcut for either::
update.callback_query.message.edit_caption(caption, *args, **kwargs)
await update.callback_query.message.edit_caption(*args, **kwargs)
or::
bot.edit_message_caption(caption=caption
inline_message_id=update.callback_query.inline_message_id,
*args, **kwargs)
await bot.edit_message_caption(
inline_message_id=update.callback_query.inline_message_id, *args, **kwargs,
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.edit_message_caption` and :meth:`telegram.Message.edit_caption`.
@@ -301,6 +308,7 @@ class CallbackQuery(TelegramObject):
async def edit_message_reply_markup(
self,
reply_markup: Optional["InlineKeyboardMarkup"] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -309,19 +317,12 @@ class CallbackQuery(TelegramObject):
) -> Union[Message, bool]:
"""Shortcut for either::
update.callback_query.message.edit_reply_markup(
reply_markup=reply_markup,
*args,
**kwargs
)
await update.callback_query.message.edit_reply_markup(*args, **kwargs)
or::
bot.edit_message_reply_markup
inline_message_id=update.callback_query.inline_message_id,
reply_markup=reply_markup,
*args,
**kwargs
await bot.edit_message_reply_markup(
inline_message_id=update.callback_query.inline_message_id, *args, **kwargs
)
For the documentation of the arguments, please see
@@ -358,6 +359,7 @@ class CallbackQuery(TelegramObject):
self,
media: "InputMedia",
reply_markup: "InlineKeyboardMarkup" = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -366,12 +368,13 @@ class CallbackQuery(TelegramObject):
) -> Union[Message, bool]:
"""Shortcut for either::
update.callback_query.message.edit_media(*args, **kwargs)
await update.callback_query.message.edit_media(*args, **kwargs)
or::
bot.edit_message_media(inline_message_id=update.callback_query.inline_message_id,
*args, **kwargs)
await bot.edit_message_media(
inline_message_id=update.callback_query.inline_message_id, *args, **kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.edit_message_media` and :meth:`telegram.Message.edit_media`.
@@ -408,26 +411,26 @@ class CallbackQuery(TelegramObject):
self,
latitude: float = None,
longitude: float = None,
location: Location = None,
reply_markup: "InlineKeyboardMarkup" = None,
horizontal_accuracy: float = None,
heading: int = None,
proximity_alert_radius: int = None,
*,
location: Location = None,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
horizontal_accuracy: float = None,
heading: int = None,
proximity_alert_radius: int = None,
) -> Union[Message, bool]:
"""Shortcut for either::
update.callback_query.message.edit_live_location(*args, **kwargs)
await update.callback_query.message.edit_live_location(*args, **kwargs)
or::
bot.edit_message_live_location(
inline_message_id=update.callback_query.inline_message_id,
*args, **kwargs
await bot.edit_message_live_location(
inline_message_id=update.callback_query.inline_message_id, *args, **kwargs
)
For the documentation of the arguments, please see
@@ -475,6 +478,7 @@ class CallbackQuery(TelegramObject):
async def stop_message_live_location(
self,
reply_markup: "InlineKeyboardMarkup" = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -483,13 +487,12 @@ class CallbackQuery(TelegramObject):
) -> Union[Message, bool]:
"""Shortcut for either::
update.callback_query.message.stop_live_location(*args, **kwargs)
await update.callback_query.message.stop_live_location(*args, **kwargs)
or::
bot.stop_message_live_location(
inline_message_id=update.callback_query.inline_message_id,
*args, **kwargs
await bot.stop_message_live_location(
inline_message_id=update.callback_query.inline_message_id, *args, **kwargs
)
For the documentation of the arguments, please see
@@ -528,6 +531,7 @@ class CallbackQuery(TelegramObject):
score: int,
force: bool = None,
disable_edit_message: bool = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -536,12 +540,13 @@ class CallbackQuery(TelegramObject):
) -> Union[Message, bool]:
"""Shortcut for either::
update.callback_query.message.set_game_score(*args, **kwargs)
await update.callback_query.message.set_game_score(*args, **kwargs)
or::
bot.set_game_score(inline_message_id=update.callback_query.inline_message_id,
*args, **kwargs)
await bot.set_game_score(
inline_message_id=update.callback_query.inline_message_id, *args, **kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.set_game_score` and :meth:`telegram.Message.set_game_score`.
@@ -581,6 +586,7 @@ class CallbackQuery(TelegramObject):
async def get_game_high_scores(
self,
user_id: Union[int, str],
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -589,12 +595,13 @@ class CallbackQuery(TelegramObject):
) -> List["GameHighScore"]:
"""Shortcut for either::
update.callback_query.message.get_game_high_score(*args, **kwargs)
await update.callback_query.message.get_game_high_score(*args, **kwargs)
or::
bot.get_game_high_scores(inline_message_id=update.callback_query.inline_message_id,
*args, **kwargs)
await bot.get_game_high_scores(
inline_message_id=update.callback_query.inline_message_id, *args, **kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.get_game_high_scores` and
@@ -627,6 +634,7 @@ class CallbackQuery(TelegramObject):
async def delete_message(
self,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -635,10 +643,9 @@ class CallbackQuery(TelegramObject):
) -> bool:
"""Shortcut for::
update.callback_query.message.delete(*args, **kwargs)
await update.callback_query.message.delete(*args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Message.delete`.
For the documentation of the arguments, please see :meth:`telegram.Message.delete`.
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
@@ -655,6 +662,7 @@ class CallbackQuery(TelegramObject):
async def pin_message(
self,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -663,10 +671,9 @@ class CallbackQuery(TelegramObject):
) -> bool:
"""Shortcut for::
update.callback_query.message.pin(*args, **kwargs)
await update.callback_query.message.pin(*args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Message.pin`.
For the documentation of the arguments, please see :meth:`telegram.Message.pin`.
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
@@ -683,6 +690,7 @@ class CallbackQuery(TelegramObject):
async def unpin_message(
self,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -691,10 +699,9 @@ class CallbackQuery(TelegramObject):
) -> bool:
"""Shortcut for::
update.callback_query.message.unpin(*args, **kwargs)
await update.callback_query.message.unpin(*args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Message.unpin`.
For the documentation of the arguments, please see :meth:`telegram.Message.unpin`.
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
@@ -718,25 +725,24 @@ class CallbackQuery(TelegramObject):
reply_to_message_id: int = None,
allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE,
reply_markup: ReplyMarkup = None,
protect_content: ODVInput[bool] = DEFAULT_NONE,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: ODVInput[bool] = DEFAULT_NONE,
) -> "MessageId":
"""Shortcut for::
update.callback_query.message.copy(
chat_id,
await update.callback_query.message.copy(
from_chat_id=update.message.chat_id,
message_id=update.message.message_id,
*args,
**kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Message.copy`.
For the documentation of the arguments, please see :meth:`telegram.Message.copy`.
Returns:
:class:`telegram.MessageId`: On success, returns the MessageId of the sent message.
+401 -108
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -124,7 +124,7 @@ class ChatInviteLink(TelegramObject):
# Optionals
self.expire_date = expire_date
self.member_limit = int(member_limit) if member_limit is not None else None
self.member_limit = member_limit
self.name = name
self.pending_join_request_count = (
int(pending_join_request_count) if pending_join_request_count is not None else None
+2
View File
@@ -114,6 +114,7 @@ class ChatJoinRequest(TelegramObject):
async def approve(
self,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -145,6 +146,7 @@ class ChatJoinRequest(TelegramObject):
async def decline(
self,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
+1
View File
@@ -45,6 +45,7 @@ class ChatMember(TelegramObject):
considered equal, if their :attr:`user` and :attr:`status` are equal.
.. versionchanged:: 20.0
* As of Bot API 5.3, :class:`ChatMember` is nothing but the base class for the subclasses
listed above and is no longer returned directly by :meth:`~telegram.Bot.get_chat`.
Therefore, most of the arguments and attributes were removed and you should no longer
+1 -1
View File
@@ -166,7 +166,7 @@ class ChatMemberUpdated(TelegramObject):
Returns:
Dict[:obj:`str`, Tuple[:class:`object`, :class:`object`]]: A dictionary mapping
attribute names to tuples of the form ``(old_value, new_value)``
attribute names to tuples of the form ``(old_value, new_value)``
"""
# we first get the names of the attributes that have changed
# user.to_dict() is unhashable, so that needs some special casing further down
+1
View File
@@ -67,6 +67,7 @@ class _BaseMedium(TelegramObject):
async def get_file(
self,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
+2 -2
View File
@@ -88,8 +88,8 @@ class Animation(_BaseThumbedMedium):
bot=bot,
)
# Required
self.width = int(width)
self.height = int(height)
self.width = width
self.height = height
self.duration = duration
# Optional
self.mime_type = mime_type
+2
View File
@@ -95,6 +95,7 @@ class ChatPhoto(TelegramObject):
async def get_small_file(
self,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
@@ -124,6 +125,7 @@ class ChatPhoto(TelegramObject):
async def get_big_file(
self,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
+7 -30
View File
@@ -18,7 +18,6 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram InputFile."""
import imghdr
import logging
import mimetypes
from pathlib import Path
@@ -35,7 +34,11 @@ class InputFile:
"""This object represents a Telegram InputFile.
.. versionchanged:: 20.0
The former attribute ``attach`` was renamed to :attr:`attach_name`.
* The former attribute ``attach`` was renamed to :attr:`attach_name`.
* Method ``is_image`` was removed. If you pass :obj:`bytes` to :paramref:`obj` and would
like to have the mime type automatically guessed, please pass :paramref:`filename`
in addition.
Args:
obj (:term:`file object` | :obj:`bytes` | :obj:`str`): An open file descriptor or the files
@@ -82,39 +85,13 @@ class InputFile:
):
filename = Path(obj.name).name # type: ignore[union-attr]
image_mime_type = self.is_image(self.input_file_content)
if image_mime_type:
self.mimetype = image_mime_type
elif filename:
self.mimetype = mimetypes.guess_type(filename)[0] or _DEFAULT_MIME_TYPE
if filename:
self.mimetype = mimetypes.guess_type(filename, strict=False)[0] or _DEFAULT_MIME_TYPE
else:
self.mimetype = _DEFAULT_MIME_TYPE
self.filename = filename or self.mimetype.replace("/", ".")
@staticmethod
def is_image(stream: bytes) -> Optional[str]:
"""Check if the content file is an image by analyzing its headers.
Args:
stream (:obj:`bytes`): A byte stream representing the content of a file.
Returns:
:obj:`str` | :obj:`None`: The mime-type of an image, if the input is an image, or
:obj:`None` else.
"""
try:
image = imghdr.what(None, stream)
if image:
return f"image/{image}"
return None
except Exception:
logger.debug(
"Could not parse file content. Assuming that file is not an image.", exc_info=True
)
return None
@property
def field_tuple(self) -> FieldTuple:
"""Field tuple representing the contents of the file for upload to the Telegram servers.
+5 -5
View File
@@ -76,13 +76,13 @@ class Location(TelegramObject):
**_kwargs: Any,
):
# Required
self.longitude = float(longitude)
self.latitude = float(latitude)
self.longitude = longitude
self.latitude = latitude
# Optionals
self.horizontal_accuracy = float(horizontal_accuracy) if horizontal_accuracy else None
self.live_period = int(live_period) if live_period else None
self.heading = int(heading) if heading else None
self.horizontal_accuracy = horizontal_accuracy
self.live_period = live_period
self.heading = heading
self.proximity_alert_radius = (
int(proximity_alert_radius) if proximity_alert_radius else None
)
+2 -2
View File
@@ -72,5 +72,5 @@ class PhotoSize(_BaseMedium):
file_id=file_id, file_unique_id=file_unique_id, file_size=file_size, bot=bot
)
# Required
self.width = int(width)
self.height = int(height)
self.width = width
self.height = height
+15 -2
View File
@@ -22,6 +22,7 @@ from typing import TYPE_CHECKING, Any, ClassVar, List, Optional
from telegram import constants
from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._files.file import File
from telegram._files.photosize import PhotoSize
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
@@ -62,6 +63,10 @@ class Sticker(_BaseThumbedMedium):
position where the mask should be placed.
file_size (:obj:`int`, optional): File size in bytes.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
premium_animation (:class:`telegram.File`, optional): Premium animation for the sticker,
if the sticker is premium.
.. versionadded:: 20.0
_kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
@@ -83,6 +88,10 @@ class Sticker(_BaseThumbedMedium):
where the mask should be placed.
file_size (:obj:`int`): Optional. File size in bytes.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
premium_animation (:class:`telegram.File`): Optional. Premium animation for the
sticker, if the sticker is premium.
.. versionadded:: 20.0
"""
@@ -94,6 +103,7 @@ class Sticker(_BaseThumbedMedium):
"mask_position",
"set_name",
"width",
"premium_animation",
)
def __init__(
@@ -110,6 +120,7 @@ class Sticker(_BaseThumbedMedium):
set_name: str = None,
mask_position: "MaskPosition" = None,
bot: "Bot" = None,
premium_animation: "File" = None,
**_kwargs: Any,
):
super().__init__(
@@ -120,14 +131,15 @@ class Sticker(_BaseThumbedMedium):
bot=bot,
)
# Required
self.width = int(width)
self.height = int(height)
self.width = width
self.height = height
self.is_animated = is_animated
self.is_video = is_video
# Optional
self.emoji = emoji
self.set_name = set_name
self.mask_position = mask_position
self.premium_animation = premium_animation
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Sticker"]:
@@ -139,6 +151,7 @@ class Sticker(_BaseThumbedMedium):
data["thumb"] = PhotoSize.de_json(data.get("thumb"), bot)
data["mask_position"] = MaskPosition.de_json(data.get("mask_position"), bot)
data["premium_animation"] = File.de_json(data.get("premium_animation"), bot)
return cls(bot=bot, **data)
+2 -1
View File
@@ -47,7 +47,8 @@ class Venue(TelegramObject):
"arts_entertainment/default", "arts_entertainment/aquarium" or "food/icecream".)
google_place_id (:obj:`str`, optional): Google Places identifier of the venue.
google_place_type (:obj:`str`, optional): Google Places type of the venue. (See
`supported types <https://developers.google.com/places/web-service/supported_types>`_.)
`supported types <https://developers.google.com/maps/documentation/places/web-service\
/supported_types>`_.)
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
+2 -2
View File
@@ -89,8 +89,8 @@ class Video(_BaseThumbedMedium):
bot=bot,
)
# Required
self.width = int(width)
self.height = int(height)
self.width = width
self.height = height
self.duration = duration
# Optional
self.mime_type = mime_type
+1 -1
View File
@@ -81,5 +81,5 @@ class VideoNote(_BaseThumbedMedium):
bot=bot,
)
# Required
self.length = int(length)
self.length = length
self.duration = duration
+1 -1
View File
@@ -75,6 +75,6 @@ class Voice(_BaseMedium):
bot=bot,
)
# Required
self.duration = int(duration)
self.duration = duration
# Optional
self.mime_type = mime_type
+2 -2
View File
@@ -68,12 +68,12 @@ class ForceReply(TelegramObject):
def __init__(
self,
selective: bool = False,
selective: bool = None,
input_field_placeholder: str = None,
**_kwargs: Any,
):
self.force_reply = True
self.selective = bool(selective)
self.selective = selective
self.input_field_placeholder = input_field_placeholder
self._id_attrs = (self.selective,)
+3 -2
View File
@@ -63,8 +63,9 @@ class Game(TelegramObject):
game message. Can be automatically edited to include current high scores for the game
when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited
using :meth:`telegram.Bot.edit_message_text`.
text_entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities that
text_entities (List[:class:`telegram.MessageEntity`]): Special entities that
appear in text, such as usernames, URLs, bot commands, etc.
This list is empty if the message does not contain text entities.
animation (:class:`telegram.Animation`): Optional. Animation that will be displayed in the
game message in chats. Upload via `BotFather <https://t.me/BotFather>`_.
@@ -182,7 +183,7 @@ class Game(TelegramObject):
return {
entity: self.parse_text_entity(entity)
for entity in (self.text_entities or [])
for entity in self.text_entities
if entity.type in types
}
+14 -5
View File
@@ -18,7 +18,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram InlineKeyboardButton."""
from typing import TYPE_CHECKING, Any, Optional
from typing import TYPE_CHECKING, Any, Optional, Union
from telegram._games.callbackgame import CallbackGame
from telegram._loginurl import LoginUrl
@@ -35,8 +35,8 @@ class InlineKeyboardButton(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`text`, :attr:`url`, :attr:`login_url`, :attr:`callback_data`,
:attr:`switch_inline_query`, :attr:`switch_inline_query_current_chat`, :attr:`callback_game`
and :attr:`pay` are equal.
:attr:`switch_inline_query`, :attr:`switch_inline_query_current_chat`, :attr:`callback_game`,
:attr:`web_app` and :attr:`pay` are equal.
Note:
* You must use exactly one of the optional fields. Mind that :attr:`callback_game` is not
@@ -62,6 +62,10 @@ class InlineKeyboardButton(TelegramObject):
* After Bot API 6.1, only ``HTTPS`` links will be allowed in :paramref:`login_url`.
.. versionchanged:: 20.0
:attr:`web_app` is considered as well when comparing objects of this type in terms of
equality.
Args:
text (:obj:`str`): Label text on the button.
url (:obj:`str`, optional): HTTP or tg:// url to be opened when the button is pressed.
@@ -78,6 +82,10 @@ class InlineKeyboardButton(TelegramObject):
callback_data (:obj:`str` | :obj:`object`, optional): Data to be sent in a callback query
to the bot when button is pressed, UTF-8 1-64 bytes. If the bot instance allows
arbitrary callback data, anything can be passed.
Tip:
The value entered here will be available in :attr:`telegram.CallbackQuery.data`.
web_app (:obj:`telegram.WebAppInfo`, optional): Description of the `Web App
<https://core.telegram.org/bots/webapps>`_ that will be launched when the user presses
the button. The Web App will be able to send an arbitrary message on behalf of the user
@@ -155,7 +163,7 @@ class InlineKeyboardButton(TelegramObject):
self,
text: str,
url: str = None,
callback_data: object = None,
callback_data: Union[str, object] = None,
switch_inline_query: str = None,
switch_inline_query_current_chat: str = None,
callback_game: CallbackGame = None,
@@ -185,6 +193,7 @@ class InlineKeyboardButton(TelegramObject):
self.url,
self.login_url,
self.callback_data,
self.web_app,
self.switch_inline_query,
self.switch_inline_query_current_chat,
self.callback_game,
@@ -205,7 +214,7 @@ class InlineKeyboardButton(TelegramObject):
return cls(**data)
def update_callback_data(self, callback_data: object) -> None:
def update_callback_data(self, callback_data: Union[str, object]) -> None:
"""
Sets :attr:`callback_data` to the passed object. Intended to be used by
:class:`telegram.ext.CallbackDataCache`.
+12 -4
View File
@@ -43,6 +43,13 @@ class InlineQuery(TelegramObject):
Note:
In Python :keyword:`from` is a reserved word use :paramref:`from_user` instead.
.. versionchanged:: 20.0
* The following are now keyword-only arguments in Bot methods:
``{read, write, connect, pool}_timeout``, :paramref:`answer.api_kwargs`,
``auto_pagination``. Use a named argument for those,
and notice that some positional arguments changed position as a result.
Args:
id (:obj:`str`): Unique identifier for this query.
from_user (:class:`telegram.User`): Sender.
@@ -118,18 +125,19 @@ class InlineQuery(TelegramObject):
results: Union[
Sequence["InlineQueryResult"], Callable[[int], Optional[Sequence["InlineQueryResult"]]]
],
cache_time: int = 300,
cache_time: int = None,
is_personal: bool = None,
next_offset: str = None,
switch_pm_text: str = None,
switch_pm_parameter: str = None,
*,
current_offset: str = None,
auto_pagination: bool = False,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
current_offset: str = None,
api_kwargs: JSONDict = None,
auto_pagination: bool = False,
) -> bool:
"""Shortcut for::
@@ -146,7 +154,7 @@ class InlineQuery(TelegramObject):
.. versionchanged:: 20.0
Raises :class:`ValueError` instead of :class:`TypeError`.
Args:
Keyword Args:
auto_pagination (:obj:`bool`, optional): If set to :obj:`True`, :attr:`offset` will be
passed as
:paramref:`current_offset <telegram.Bot.answer_inline_query.current_offset>` to
@@ -116,8 +116,8 @@ class InlineQueryResultLocation(InlineQueryResult):
):
# Required
super().__init__(InlineQueryResultType.LOCATION, id)
self.latitude = float(latitude)
self.longitude = float(longitude)
self.latitude = latitude
self.longitude = longitude
self.title = title
# Optionals
@@ -127,8 +127,8 @@ class InlineQueryResultLocation(InlineQueryResult):
self.thumb_url = thumb_url
self.thumb_width = thumb_width
self.thumb_height = thumb_height
self.horizontal_accuracy = float(horizontal_accuracy) if horizontal_accuracy else None
self.heading = int(heading) if heading else None
self.horizontal_accuracy = horizontal_accuracy
self.heading = heading
self.proximity_alert_radius = (
int(proximity_alert_radius) if proximity_alert_radius else None
)

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