Compare commits

...

63 Commits

Author SHA1 Message Date
Hinrich Mahler 4aedb33d37 Bump version to v20.2 2023-03-25 13:25:59 +01:00
Bibo-Joshi 4ddc36c625 Documentation Improvements (#3565, #3600)
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
Co-authored-by: poolitzer <github@poolitzer.eu>
Co-authored-by: Louis Wang <beiluonever@users.noreply.github.com>
2023-03-25 12:48:34 +01:00
dependabot[bot] 311f88a716 Bump pytest-asyncio from 0.20.3 to 0.21.0 (#3624) 2023-03-25 12:25:57 +01:00
dependabot[bot] 179cb49dbc Bump furo from 2022.12.7 to 2023.3.23 (#3625) 2023-03-25 12:25:36 +01:00
Bibo-Joshi 512e390738 API 6.6 (#3584)
Co-authored-by: poolitzer <github@poolitzer.eu>
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2023-03-25 11:47:26 +01:00
dependabot[bot] 33b677aeb4 Bump pytest-xdist from 3.2.0 to 3.2.1 (#3606) 2023-03-19 10:54:03 +01:00
Poolitzer 800598ced4 Revert to HTTP/1.1 as Default and make HTTP/2 an Optional Dependency (#3576)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2023-03-12 16:30:39 +01:00
pre-commit-ci[bot] ec20f27a82 pre-commit autoupdate (#3577)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-03-08 20:46:51 +01:00
Bibo-Joshi cd59c1c075 Handle Symbolic Links in was_called_by (#3552)
Co-authored-by: hyfc <myloxyloto2012@gmail.com>
2023-03-06 21:59:01 +01:00
dependabot[bot] 52b0f2c3c9 Update apscheduler requirement from ~=3.10.0 to ~=3.10.1 (#3572)
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2023-03-06 21:09:29 +01:00
dependabot[bot] 598f44f4c2 Bump pytest from 7.2.1 to 7.2.2 (#3573) 2023-03-05 16:21:57 +01:00
Bibo-Joshi 22d0dd1301 Tidy Up Tests Directory (#3553) 2023-02-22 20:19:46 +01:00
sam-mosleh c6b6b0a370 Enhance Application.create_task (#3543) 2023-02-20 19:53:27 +01:00
Bibo-Joshi ee6c8a5995 Make Type Completeness Workflow Usable for PRs from Forks (#3551) 2023-02-13 20:39:12 +01:00
dependabot[bot] d5a1a48145 Bump pytest-xdist from 3.1.0 to 3.2.0 (#3550) 2023-02-11 17:42:10 +01:00
Harshil 963edbf191 Refactor and Overhaul the Test Suite (#3426) 2023-02-11 10:45:17 +01:00
dependabot[bot] 43c3c8f568 Bump sphinxcontrib-mermaid from 0.7.1 to 0.8 (#3549) 2023-02-11 10:43:38 +01:00
Hinrich Mahler 49ea8d39fb Bump version to v20.1 2023-02-09 20:58:22 +01:00
Harshil 7e86e8be14 Update cryptography requirement to >=39.0.1 to address Vulnerability (#3539) 2023-02-09 19:32:50 +01:00
Bibo-Joshi 5cff9adb55 Fix CI on Python 3.11 + Windows (#3547) 2023-02-09 18:58:36 +01:00
Harshil 217a5f929e Add Some Graphic Elements to Docs (#3535)
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
2023-02-08 17:43:14 +01:00
pre-commit-ci[bot] 007f432ee4 pre-commit autoupdate (#3537)
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
2023-02-08 17:41:10 +01:00
Poolitzer 23a685335b API 6.5 (#3530)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2023-02-08 11:47:21 +01:00
Bibo-Joshi 9953216980 Documentation Improvements (#3464, #3483, #3484, #3497, #3512, #3501, #3515, #3523, #3498, #3529)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Shivam Saini <51438830+shivamsn97@users.noreply.github.com>
Co-authored-by: Aditya Yadav <adityayadav11082@gmail.com>
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
Co-authored-by: Crsi <47722349+CrsiX@users.noreply.github.com>
Co-authored-by: poolitzer <github@poolitzer.eu>
Co-authored-by: Aditya <clot27@apx_managed.vanilla>
2023-02-05 18:09:55 +01:00
Bibo-Joshi bacdeb37fd Increase Verbosity of Type Completeness CI Job (#3531) 2023-02-04 16:45:47 +01:00
dependabot[bot] a0f98b241e Update apscheduler requirement from ~=3.9.1 to ~=3.10.0 (#3532)
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2023-02-04 09:21:28 +01:00
Bibo-Joshi 23d0bd8fe3 Explicit Type Annotations (#3508) 2023-02-02 18:55:07 +01:00
Poolitzer 1701950a1d Bump isort to 5.12.0 (#3525) 2023-02-01 22:11:56 +01:00
dependabot[bot] 851f7ff0b3 Update cachetools requirement from ~=5.2.1 to ~=5.3.0 (#3520)
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2023-01-28 12:36:11 +01:00
Aditya 359232e6c7 Check for 3D Arrays in check_keyboard_type (#3514) 2023-01-22 12:11:52 +01:00
dependabot[bot] 9782510779 Bump pytest from 7.2.0 to 7.2.1 (#3513) 2023-01-21 11:01:25 +01:00
Harshil deb6cb19b3 Allow to Adjust HTTP Version and Use HTTP/2 by Default (#3506) 2023-01-20 21:15:02 +01:00
Bibo-Joshi 21ebdbc973 Lock Inactive Threads Only Once Each Day (#3510) 2023-01-20 20:49:20 +01:00
Dmitry Kolomatskiy 54d0294f92 Enhance chatmemberbot Example (#3500) 2023-01-19 21:33:16 +01:00
Harshil 5693add136 Improve Config for ruff and Bump to v0.0.222 (#3507) 2023-01-15 16:17:02 +01:00
Bibo-Joshi 3dd7d84fa5 Improve Error Message for NetworkError (#3505) 2023-01-15 13:40:20 +01:00
Harshil 4ebcec2b91 Improve Warning for days Parameter of JobQueue.run_daily (#3503) 2023-01-14 18:57:08 +01:00
dependabot[bot] 200b623263 Update cachetools requirement from ~=5.2.0 to ~=5.2.1 (#3502)
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2023-01-14 17:41:47 +01:00
dependabot[bot] c64bd7a715 Update httpx requirement from ~=0.23.1 to ~=0.23.3 (#3489)
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2023-01-07 13:39:23 +01:00
Aditya bbb9fcaaa5 Add ruff to pre-commit Hooks (#3488) 2023-01-06 16:19:49 +01:00
Viicos d48fa71ec5 Add Chat.effective_name Convenience Property (#3485) 2023-01-06 08:15:56 +01:00
Harshil f9cbddd10a Store Documentation Builts as GitHub Actions Artifacts (#3468) 2023-01-06 08:14:09 +01:00
Harshil 2797d9d305 Cache Dependencies on GitHub Actions (#3469) 2023-01-06 08:13:20 +01:00
Aditya 19302bce25 Add Application(Builder).post_stop (#3466) 2023-01-04 16:48:48 +01:00
Aditya 3507cb13e6 Fix Dependency Warning Typo (#3474) 2023-01-03 18:50:06 +01:00
pre-commit-ci[bot] 6b59365464 pre-commit autoupdate (#3470) 2023-01-03 13:27:56 +01:00
dependabot[bot] 74da17153b Bump dessant/lock-threads from 3.0.0 to 4.0.0 (#3462) 2023-01-02 21:55:21 +01:00
dependabot[bot] 97e6e7e206 Bump actions/stale from 6 to 7 (#3461) 2023-01-02 21:53:44 +01:00
Bibo-Joshi d1159cd5ac Stabilize Tests on Closing and Hiding the General Forum Topic (#3460) 2023-01-02 19:45:07 +01:00
Bibo-Joshi 51ad4d76d0 Update Copyright to 2023 (#3459) 2023-01-01 21:31:29 +01:00
Hinrich Mahler 171953f109 Bump version to v20.0 2023-01-01 17:20:54 +01:00
Harshil 606773d8f0 API 6.4 (#3449)
Co-authored-by: poolitzer <github@poolitzer.eu>
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2023-01-01 17:00:49 +01:00
Bibo-Joshi f408b1a2dd Documentation Improvements (#3428, #3423, #3429, #3441, #3404, #3443)
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
Co-authored-by: Viicos <65306057+Viicos@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Eisberge <22561095+Eisberge@users.noreply.github.com>
Co-authored-by: Joshua Tang <joshuaystang@gmail.com>
2023-01-01 16:24:00 +01:00
Harshil 3e7ab7e7af Downgrade sphinx to 5.3.0 to Fix Search (#3457) 2023-01-01 15:48:48 +01:00
Aditya 456b81d22a Allow Sequence Input for Bot Methods (#3412)
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2023-01-01 14:24:30 +01:00
Bibo-Joshi cb90814829 Update Link-Check CI and Replace a Dead Link (#3456) 2023-01-01 13:48:24 +01:00
Bibo-Joshi 7b61a30fb1 Freeze Classes Without Arguments (#3453) 2023-01-01 13:04:37 +01:00
dependabot[bot] f3a9b74445 Bump sphinx from 5.3.0 to 6.0.0 (#3450)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2022-12-31 16:59:49 +01:00
Dmitry Kolomatskiy d996e8f9c9 Add New Constants (#3444) 2022-12-30 14:09:06 +01:00
Bibo-Joshi 0a6725852f Override Bot.__deepcopy__ to Raise TypeError (#3446) 2022-12-30 10:50:49 +01:00
Bibo-Joshi b8fbb89fae Add Log Decorator to Bot.get_webhook_info (#3442) 2022-12-27 19:02:50 +01:00
Bibo-Joshi f3650364b9 Add Documention On Verifying Releases (#3436) 2022-12-21 16:55:58 +01:00
Bibo-Joshi 5b629ede56 Drop Undocumented Job.__lt__ (#3432) 2022-12-19 18:32:53 +01:00
594 changed files with 21638 additions and 11121 deletions
+6 -28
View File
@@ -84,35 +84,13 @@ Here's how to make a one-off code change.
- In addition, PTB uses some formatting/styling and linting tools in the pre-commit setup. Some of those tools also have command line tools that can help to run these tools outside of the pre-commit step. If you'd like to leverage that, please have a look at the `pre-commit config file`_ for an overview of which tools (and which versions of them) are used. For example, we use `Black`_ for code formatting. Plugins for Black exist for some `popular editors`_. You can use those instead of manually formatting everything.
- Please ensure that the code you write is well-tested.
- Please ensure that the code you write is well-tested and that all automated tests still pass. We
have dedicated an `testing page`_ to help you with that.
- In addition to that, we provide the `dev` marker for pytest. If you write one or multiple tests and want to run only those, you can decorate them via `@pytest.mark.dev` and then run it with minimal overhead with `pytest ./path/to/test_file.py -m dev`.
- Dont break backward compatibility.
- Don't break backward compatibility.
- Add yourself to the AUTHORS.rst_ file in an alphabetical fashion.
- Before making a commit ensure that all automated tests still pass:
.. code-block:: bash
$ pytest -v
Since the tests can take a while to run, you can speed things up by running them in parallel
using `pytest-xdist`_ (note that this may effect the result of the test in some rare cases):
.. code-block:: bash
$ pytest -v -n auto --dist=loadfile
To run ``test_official`` (particularly useful if you made API changes), run
.. code-block:: bash
$ export TEST_OFFICIAL=true
prior to running the tests.
- If you want run style & type checks before committing run
.. code-block:: bash
@@ -185,7 +163,7 @@ doc strings don't have a separate documentation site they generate, instead, the
User facing documentation
-------------------------
We use `sphinx`_ to generate static HTML docs. To build them, first make sure you have the required dependencies:
We use `sphinx`_ to generate static HTML docs. To build them, first make sure you're running Python 3.9 or above and have the required dependencies:
.. code-block:: bash
@@ -205,7 +183,7 @@ or, if you don't have ``make`` available (e.g. on Windows):
Once the process terminates, you can view the built documentation by opening ``docs/build/html/index.html`` with a browser.
- Add ``.. versionadded:: version``, ``.. versionchanged:: version`` or ``.. deprecated:: version`` to the associated documentation of your changes, depending on what kind of change you made. This only applies if the change you made is visible to an end user. The directives should be added to class/method descriptions if their general behaviour changed and to the description of all arguments & attributes that changed.
- Add ``.. versionadded:: NEXT.VERSION``, ``.. versionchanged:: NEXT.VERSION`` or ``.. deprecated:: NEXT.VERSION`` to the associated documentation of your changes, depending on what kind of change you made. This only applies if the change you made is visible to an end user. The directives should be added to class/method descriptions if their general behaviour changed and to the description of all arguments & attributes that changed.
Dev facing documentation
------------------------
@@ -287,4 +265,4 @@ break the API classes. For example:
.. _`RTD build`: https://docs.python-telegram-bot.org/en/doc-fixes
.. _`CSI`: https://standards.mousepawmedia.com/en/stable/csi.html
.. _`section`: #documenting
.. _`pytest-xdist`: https://github.com/pytest-dev/pytest-xdist
.. _`testing page`: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/tests/README.rst
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ${{matrix.os}}
strategy:
matrix:
python-version: [3.7]
python-version: [3.9]
os: [ubuntu-latest]
fail-fast: False
steps:
+17 -2
View File
@@ -5,7 +5,7 @@ on:
- master
- doc-fixes
push:
branches:
branches:
- master
- doc-fixes
@@ -15,7 +15,7 @@ jobs:
runs-on: ${{matrix.os}}
strategy:
matrix:
python-version: [3.7]
python-version: [3.9]
os: [ubuntu-latest]
fail-fast: False
steps:
@@ -24,9 +24,24 @@ jobs:
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: '**/requirements*.txt'
- name: Install dependencies
run: |
python -W ignore -m pip install --upgrade pip
python -W ignore -m pip install -r requirements-all.txt
- name: Test autogeneration of admonitions
run: pytest -v --tb=short tests/docs/admonition_inserter.py
- name: Build docs
run: sphinx-build docs/source docs/build/html -W --keep-going -j auto
- name: Upload docs
uses: actions/upload-artifact@v3
with:
name: HTML Docs
retention-days: 7
path: |
# Exclude the .doctrees folder and .buildinfo file from the artifact
# since they are not needed and add to the size
docs/build/html/*
!docs/build/html/.doctrees
!docs/build/html/.buildinfo
+1 -2
View File
@@ -3,13 +3,12 @@ name: 'Lock Closed Threads'
on:
schedule:
- cron: '8 4 * * *'
- cron: '42 17 * * *'
jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v3.0.0
- uses: dessant/lock-threads@v4.0.0
with:
github-token: ${{ github.token }}
issue-inactive-days: '7'
+1 -1
View File
@@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v6
- uses: actions/stale@v7
with:
# PRs never get stale
days-before-stale: 3
File diff suppressed because one or more lines are too long
+69
View File
@@ -0,0 +1,69 @@
name: Check Type Completeness
on:
pull_request:
branches:
- master
push:
branches:
- master
jobs:
test-type-completeness:
name: test-type-completeness
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: git fetch --depth=1 # https://github.com/actions/checkout/issues/329#issuecomment-674881489
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: 3.9
cache: 'pip'
cache-dependency-path: '**/requirements*.txt'
- name: Install Pyright
run: |
python -W ignore -m pip install pyright~=1.1.291
- name: Get PR Completeness
# Must run before base completeness, as base completeness will checkout the base branch
# And we can't go back to the PR branch after that in case the PR is coming from a fork
run: |
pip install . -U
pyright --verifytypes telegram --ignoreexternal --outputjson > pr.json || true
pyright --verifytypes telegram --ignoreexternal > pr.readable || true
- name: Get Base Completeness
run: |
git checkout ${{ github.base_ref }}
pip install . -U
pyright --verifytypes telegram --ignoreexternal --outputjson > base.json || true
- name: Compare Completeness
uses: jannekem/run-python-script-action@v1
with:
script: |
import json
import os
from pathlib import Path
base = float(
json.load(open("base.json", "rb"))["typeCompleteness"]["completenessScore"]
)
pr = float(
json.load(open("pr.json", "rb"))["typeCompleteness"]["completenessScore"]
)
base_text = f"After this PR, type completeness will be {round(pr, 3)}."
if pr < (base - 0.1):
text = f"This PR decreases type completeness by {round(base - pr, 3)}. ❌"
set_summary(text)
print(Path("pr.readable").read_text(encoding="utf-8"))
error(f"{text}\n{base_text}")
exit(1)
elif pr > (base + 0.1):
text = f"This PR increases type completeness by {round(pr - base, 3)}. ✨"
set_summary(text)
if pr < 1:
print(Path("pr.readable").read_text(encoding="utf-8"))
print(f"{text}\n{base_text}")
else:
text = f"This PR does not change type completeness by more than 0.1. ✅"
set_summary(text)
print(Path("pr.readable").read_text(encoding="utf-8"))
print(f"{text}\n{base_text}")
+2
View File
@@ -51,6 +51,8 @@ nosetests.xml
coverage.xml
*,cover
.coveralls.yml
.testmondata
.testmondata-journal
# Translations
*.mo
+26 -14
View File
@@ -9,7 +9,7 @@ ci:
repos:
- repo: https://github.com/psf/black
rev: 22.10.0
rev: 23.1.0
hooks:
- id: black
args:
@@ -20,7 +20,7 @@ repos:
hooks:
- id: flake8
- repo: https://github.com/PyCQA/pylint
rev: v2.15.8
rev: v2.16.4
hooks:
- id: pylint
files: ^(telegram|examples)/.*\.py$
@@ -31,14 +31,14 @@ repos:
- --jobs=0
additional_dependencies:
- httpx~=0.23.0
- httpx~=0.23.3
- tornado~=6.2
- APScheduler~=3.9.1
- cachetools~=5.2.0
- APScheduler~=3.10.1
- cachetools~=5.3.0
- aiolimiter~=1.0.0
- . # this basically does `pip install -e .`
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.991
rev: v1.0.1
hooks:
- id: mypy
name: mypy-ptb
@@ -47,10 +47,10 @@ repos:
- types-pytz
- types-cryptography
- types-cachetools
- httpx~=0.23.0
- httpx~=0.23.3
- tornado~=6.2
- APScheduler~=3.9.1
- cachetools~=5.2.0
- APScheduler~=3.10.1
- cachetools~=5.3.0
- aiolimiter~=1.0.0
- . # this basically does `pip install -e .`
- id: mypy
@@ -61,21 +61,33 @@ repos:
- --follow-imports=silent
additional_dependencies:
- tornado~=6.2
- APScheduler~=3.9.1
- cachetools~=5.2.0
- APScheduler~=3.10.1
- cachetools~=5.3.0
- . # this basically does `pip install -e .`
- repo: https://github.com/asottile/pyupgrade
rev: v3.3.0
rev: v3.3.1
hooks:
- id: pyupgrade
files: ^(telegram|examples|tests)/.*\.py$
files: ^(telegram|examples|tests|docs)/.*\.py$
args:
- --py37-plus
- repo: https://github.com/pycqa/isort
rev: 5.10.1
rev: 5.12.0
hooks:
- id: isort
name: isort
args:
- --diff
- --check
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: 'v0.0.254'
hooks:
- id: ruff
name: ruff
files: ^(telegram|examples)/.*\.py$
additional_dependencies:
- httpx~=0.23.3
- tornado~=6.2
- APScheduler~=3.10.1
- cachetools~=5.3.0
- aiolimiter~=1.0.0
+3
View File
@@ -74,6 +74,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `LRezende <https://github.com/lrezende>`_
- `macrojames <https://github.com/macrojames>`_
- `Matheus Lemos <https://github.com/mlemosf>`_
- `Michael Dix <https://github.com/Eisberge>`_
- `Michael Elovskikh <https://github.com/wronglink>`_
- `miles <https://github.com/miles170>`_
- `Mischa Krüger <https://github.com/Makman2>`_
@@ -99,8 +100,10 @@ The following wonderful people contributed directly or indirectly to this projec
- `Riko Naka <https://github.com/rikonaka>`_
- `Rizlas <https://github.com/rizlas>`_
- `Sahil Sharma <https://github.com/sahilsharma811>`_
- `Sam Mosleh <https://github.com/sam-mosleh>`_
- `Sascha <https://github.com/saschalalala>`_
- `Shelomentsev D <https://github.com/shelomentsevd>`_
- `Shivam Saini <https://github.com/shivamsn97>`_
- `Simon Schürrle <https://github.com/SitiSchu>`_
- `sooyhwang <https://github.com/sooyhwang>`_
- `syntx <https://github.com/syntx>`_
+203 -2
View File
@@ -1,6 +1,207 @@
=========
Changelog
=========
Version 20.2
============
*Released 2023-03-25*
This is the technical changelog for version 20.2. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support for API 6.6 (`#3584`_)
- Revert to HTTP/1.1 as Default and make HTTP/2 an Optional Dependency (`#3576`_)
Minor Changes, Documentation Improvements and CI
------------------------------------------------
- Documentation Improvements (`#3565`_, `#3600`_)
- Handle Symbolic Links in ``was_called_by`` (`#3552`_)
- Tidy Up Tests Directory (`#3553`_)
- Enhance ``Application.create_task`` (`#3543`_)
- Make Type Completeness Workflow Usable for ``PRs`` from Forks (`#3551`_)
- Refactor and Overhaul the Test Suite (`#3426`_)
Dependencies
------------
- Bump ``pytest-asyncio`` from 0.20.3 to 0.21.0 (`#3624`_)
- Bump ``furo`` from 2022.12.7 to 2023.3.23 (`#3625`_)
- Bump ``pytest-xdist`` from 3.2.0 to 3.2.1 (`#3606`_)
- ``pre-commit`` autoupdate (`#3577`_)
- Update ``apscheduler`` requirement from ~=3.10.0 to ~=3.10.1 (`#3572`_)
- Bump ``pytest`` from 7.2.1 to 7.2.2 (`#3573`_)
- Bump ``pytest-xdist`` from 3.1.0 to 3.2.0 (`#3550`_)
- Bump ``sphinxcontrib-mermaid`` from 0.7.1 to 0.8 (`#3549`_)
.. _`#3584`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3584
.. _`#3576`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3576
.. _`#3565`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3565
.. _`#3600`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3600
.. _`#3552`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3552
.. _`#3553`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3553
.. _`#3543`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3543
.. _`#3551`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3551
.. _`#3426`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3426
.. _`#3624`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3624
.. _`#3625`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3625
.. _`#3606`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3606
.. _`#3577`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3577
.. _`#3572`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3572
.. _`#3573`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3573
.. _`#3550`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3550
.. _`#3549`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3549
Version 20.1
============
*Released 2023-02-09*
This is the technical changelog for version 20.1. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support for Bot API 6.5 (`#3530`_)
New Features
------------
- Add ``Application(Builder).post_stop`` (`#3466`_)
- Add ``Chat.effective_name`` Convenience Property (`#3485`_)
- Allow to Adjust HTTP Version and Use HTTP/2 by Default (`#3506`_)
Documentation Improvements
--------------------------
- Enhance ``chatmemberbot`` Example (`#3500`_)
- Automatically Generate Cross-Reference Links (`#3501`_, `#3529`_, `#3523`_)
- Add Some Graphic Elements to Docs (`#3535`_)
- Various Smaller Improvements (`#3464`_, `#3483`_, `#3484`_, `#3497`_, `#3512`_, `#3515`_, `#3498`_)
Minor Changes, Documentation Improvements and CI
------------------------------------------------
- Update Copyright to 2023 (`#3459`_)
- Stabilize Tests on Closing and Hiding the General Forum Topic (`#3460`_)
- Fix Dependency Warning Typo (`#3474`_)
- Cache Dependencies on ``GitHub`` Actions (`#3469`_)
- Store Documentation Builts as ``GitHub`` Actions Artifacts (`#3468`_)
- Add ``ruff`` to ``pre-commit`` Hooks (`#3488`_)
- Improve Warning for ``days`` Parameter of ``JobQueue.run_daily`` (`#3503`_)
- Improve Error Message for ``NetworkError`` (`#3505`_)
- Lock Inactive Threads Only Once Each Day (`#3510`_)
- Bump ``pytest`` from 7.2.0 to 7.2.1 (`#3513`_)
- Check for 3D Arrays in ``check_keyboard_type`` (`#3514`_)
- Explicit Type Annotations (`#3508`_)
- Increase Verbosity of Type Completeness CI Job (`#3531`_)
- Fix CI on Python 3.11 + Windows (`#3547`_)
Dependencies
------------
- Bump ``actions/stale`` from 6 to 7 (`#3461`_)
- Bump ``dessant/lock-threads`` from 3.0.0 to 4.0.0 (`#3462`_)
- ``pre-commit`` autoupdate (`#3470`_)
- Update ``httpx`` requirement from ~=0.23.1 to ~=0.23.3 (`#3489`_)
- Update ``cachetools`` requirement from ~=5.2.0 to ~=5.2.1 (`#3502`_)
- Improve Config for ``ruff`` and Bump to ``v0.0.222`` (`#3507`_)
- Update ``cachetools`` requirement from ~=5.2.1 to ~=5.3.0 (`#3520`_)
- Bump ``isort`` to 5.12.0 (`#3525`_)
- Update ``apscheduler`` requirement from ~=3.9.1 to ~=3.10.0 (`#3532`_)
- ``pre-commit`` autoupdate (`#3537`_)
- Update ``cryptography`` requirement to >=39.0.1 to address Vulnerability (`#3539`_)
.. _`#3530`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3530
.. _`#3466`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3466
.. _`#3485`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3485
.. _`#3506`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3506
.. _`#3500`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3500
.. _`#3501`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3501
.. _`#3529`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3529
.. _`#3523`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3523
.. _`#3535`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3535
.. _`#3464`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3464
.. _`#3483`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3483
.. _`#3484`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3484
.. _`#3497`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3497
.. _`#3512`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3512
.. _`#3515`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3515
.. _`#3498`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3498
.. _`#3459`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3459
.. _`#3460`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3460
.. _`#3474`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3474
.. _`#3469`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3469
.. _`#3468`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3468
.. _`#3488`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3488
.. _`#3503`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3503
.. _`#3505`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3505
.. _`#3510`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3510
.. _`#3513`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3513
.. _`#3514`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3514
.. _`#3508`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3508
.. _`#3531`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3531
.. _`#3547`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3547
.. _`#3461`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3461
.. _`#3462`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3462
.. _`#3470`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3470
.. _`#3489`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3489
.. _`#3502`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3502
.. _`#3507`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3507
.. _`#3520`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3520
.. _`#3525`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3525
.. _`#3532`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3532
.. _`#3537`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3537
.. _`#3539`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3539
Version 20.0
============
*Released 2023-01-01*
This is the technical changelog for version 20.0. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support For Bot API 6.4 (`#3449`_)
Minor Changes, Documentation Improvements and CI
------------------------------------------------
- Documentation Improvements (`#3428`_, `#3423`_, `#3429`_, `#3441`_, `#3404`_, `#3443`_)
- Allow ``Sequence`` Input for Bot Methods (`#3412`_)
- Update Link-Check CI and Replace a Dead Link (`#3456`_)
- Freeze Classes Without Arguments (`#3453`_)
- Add New Constants (`#3444`_)
- Override ``Bot.__deepcopy__`` to Raise ``TypeError`` (`#3446`_)
- Add Log Decorator to ``Bot.get_webhook_info`` (`#3442`_)
- Add Documentation On Verifying Releases (`#3436`_)
- Drop Undocumented ``Job.__lt__`` (`#3432`_)
Dependencies
------------
- Downgrade ``sphinx`` to 5.3.0 to Fix Search (`#3457`_)
- Bump ``sphinx`` from 5.3.0 to 6.0.0 (`#3450`_)
.. _`#3449`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3449
.. _`#3428`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3428
.. _`#3423`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3423
.. _`#3429`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3429
.. _`#3441`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3441
.. _`#3404`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3404
.. _`#3443`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3443
.. _`#3412`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3412
.. _`#3456`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3456
.. _`#3453`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3453
.. _`#3444`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3444
.. _`#3446`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3446
.. _`#3442`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3442
.. _`#3436`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3436
.. _`#3432`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3432
.. _`#3457`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3457
.. _`#3450`: https://github.com/python-telegram-bot/python-telegram-bot/pull/3450
Version 20.0b0
==============
*Released 2022-12-15*
@@ -10,7 +211,7 @@ This is the technical changelog for version 20.0b0. More elaborate release notes
Major Changes
-------------
- Make `TelegramObject` Immutable (`#3249`_)
- Make ``TelegramObject`` Immutable (`#3249`_)
Minor Changes, Documentation Improvements and CI
------------------------------------------------
@@ -1956,7 +2157,7 @@ Changes
- Lots of small improvements to our tests and documentation.
.. _`see docs`: https://docs.python-telegram-bot.org/en/stable/telegram.ext.dispatcher.html#telegram.ext.Dispatcher.add_handler
.. _`see docs`: https://docs.python-telegram-bot.org/en/v13.11/telegram.ext.dispatcher.html?highlight=Dispatcher.add_handler#telegram.ext.Dispatcher.add_handler
.. _`#777`: https://github.com/python-telegram-bot/python-telegram-bot/pull/777
.. _`#806`: https://github.com/python-telegram-bot/python-telegram-bot/pull/806
.. _`#766`: https://github.com/python-telegram-bot/python-telegram-bot/pull/766
+23 -9
View File
@@ -14,7 +14,7 @@
:target: https://pypi.org/project/python-telegram-bot/
:alt: Supported Python versions
.. image:: https://img.shields.io/badge/Bot%20API-6.3-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-6.6-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions
@@ -93,7 +93,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
Telegram API support
====================
All types and methods of the Telegram Bot API **6.2** are supported.
All types and methods of the Telegram Bot API **6.6** are supported.
Installing
==========
@@ -114,6 +114,18 @@ You can also install ``python-telegram-bot`` from source, though this is usually
$ cd python-telegram-bot
$ python setup.py install
Verifying Releases
------------------
We sign all the releases with a GPG key.
The signatures are uploaded to both the `GitHub releases page <https://github.com/python-telegram-bot/python-telegram-bot/releases>`_ and the `PyPI project <https://pypi.org/project/python-telegram-bot/>`_ and end with a suffix ``.asc``.
Please find the public keys `here <https://github.com/python-telegram-bot/python-telegram-bot/tree/master/public_keys>`_.
The keys are named in the format ``<first_version>-<last_version>.gpg`` or ``<first_version>-current.gpg`` if the key is currently being used for new releases.
In addition, the GitHub release page also contains the sha1 hashes of the release files in the files with the suffix ``.sha1``.
This allows you to verify that a release file that you downloaded was indeed provided by the ``python-telegram-bot`` team.
Dependencies & Their Versions
-----------------------------
@@ -123,7 +135,8 @@ As these features are *optional*, the corresponding 3rd party dependencies are n
Instead, they are listed as optional dependencies.
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
The only required dependency is `httpx ~= 0.23.0 <https://www.python-httpx.org>`_ for ``telegram.request.HTTPXRequest``, the default networking backend.
The only required dependency is `httpx ~= 0.23.3 <https://www.python-httpx.org>`_ for
``telegram.request.HTTPXRequest``, the default networking backend.
``python-telegram-bot`` is most useful when used along with additional libraries.
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the (optional) dependencies.
@@ -135,12 +148,13 @@ Optional Dependencies
PTB can be installed with optional dependencies:
* ``pip install python-telegram-bot[passport]`` installs the `cryptography>=3.0 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
* ``pip install python-telegram-bot[socks]`` installs ``httpx[socks]``. Use this, if you want to work behind a Socks5 server.
* ``pip install python-telegram-bot[rate-limiter]`` installs ``aiolimiter~=1.0.0``. Use this, if you want to use ``telegram.ext.AIORateLimiter``.
* ``pip install python-telegram-bot[webhooks]`` installs the `tornado~=6.2 <https://www.tornadoweb.org/en/stable/>`_ library. Use this, if you want to use ``telegram.ext.Updater.start_webhook``/``telegram.ext.Application.start_webhook``.
* ``pip install python-telegram-bot[callback-data]`` installs the `cachetools~=5.2.0 <https://cachetools.readthedocs.io/en/latest/>`_ library. Use this, if you want to use `arbitrary callback_data <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Arbitrary-callback_data>`_.
* ``pip install python-telegram-bot[job-queue]`` installs the `APScheduler~=3.9.1 <https://apscheduler.readthedocs.io/en/3.x/>`_ library and enforces `pytz>=2018.6 <https://pypi.org/project/pytz/>`_, where ``pytz`` is a dependency of ``APScheduler``. Use this, if you want to use the ``telegram.ext.JobQueue``.
* ``pip install python-telegram-bot[passport]`` installs the `cryptography>=39.0.1 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
* ``pip install python-telegram-bot[socks]`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
* ``pip install python-telegram-bot[http2]`` installs `httpx[http2] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to use HTTP/2.
* ``pip install python-telegram-bot[rate-limiter]`` installs `aiolimiter~=1.0.0 <https://aiolimiter.readthedocs.io/en/stable/>`_. Use this, if you want to use ``telegram.ext.AIORateLimiter``.
* ``pip install python-telegram-bot[webhooks]`` installs the `tornado~=6.2 <https://www.tornadoweb.org/en/stable/>`_ library. Use this, if you want to use ``telegram.ext.Updater.start_webhook``/``telegram.ext.Application.run_webhook``.
* ``pip install python-telegram-bot[callback-data]`` installs the `cachetools~=5.3.0 <https://cachetools.readthedocs.io/en/latest/>`_ library. Use this, if you want to use `arbitrary callback_data <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Arbitrary-callback_data>`_.
* ``pip install python-telegram-bot[job-queue]`` installs the `APScheduler~=3.10.1 <https://apscheduler.readthedocs.io/en/3.x/>`_ library and enforces `pytz>=2018.6 <https://pypi.org/project/pytz/>`_, where ``pytz`` is a dependency of ``APScheduler``. Use this, if you want to use the ``telegram.ext.JobQueue``.
To install multiple optional dependencies, separate them by commas, e.g. ``pip install python-telegram-bot[socks,webhooks]``.
+20 -6
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.3-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-6.6-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions
@@ -34,7 +34,7 @@
:target: https://github.com/python-telegram-bot/python-telegram-bot/
:alt: Github Actions workflow
.. image:: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot
.. image:: https://codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg
:target: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot
:alt: Code coverage
@@ -89,7 +89,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
Telegram API support
====================
All types and methods of the Telegram Bot API **6.2** are supported.
All types and methods of the Telegram Bot API **6.6** are supported.
Installing
==========
@@ -115,6 +115,18 @@ Note
Installing the ``.tar.gz`` archive available on PyPi directly via ``pip`` will *not* work as expected, as ``pip`` does not recognize that it should use ``setup-raw.py`` instead of ``setup.py``.
Verifying Releases
------------------
We sign all the releases with a GPG key.
The signatures are uploaded to both the `GitHub releases page <https://github.com/python-telegram-bot/python-telegram-bot/releases>`_ and the `PyPI project <https://pypi.org/project/python-telegram-bot/>`_ and end with a suffix ``.asc``.
Please find the public keys `here <https://github.com/python-telegram-bot/python-telegram-bot/tree/master/public_keys>`_.
The keys are named in the format ``<first_version>-<last_version>.gpg`` or ``<first_version>-current.gpg`` if the key is currently being used for new releases.
In addition, the GitHub release page also contains the sha1 hashes of the release files in the files with the suffix ``.sha1``.
This allows you to verify that a release file that you downloaded was indeed provided by the ``python-telegram-bot`` team.
Dependencies & Their Versions
-----------------------------
@@ -124,7 +136,8 @@ As these features are *optional*, the corresponding 3rd party dependencies are n
Instead, they are listed as optional dependencies.
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
The only required dependency is `httpx ~= 0.23.0 <https://www.python-httpx.org>`_ for ``telegram.request.HTTPXRequest``, the default networking backend.
The only required dependency is `httpx ~= 0.23.3 <https://www.python-httpx.org>`_ for
``telegram.request.HTTPXRequest``, the default networking backend.
``python-telegram-bot`` is most useful when used along with additional libraries.
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the (optional) dependencies.
@@ -136,8 +149,9 @@ Optional Dependencies
PTB can be installed with optional dependencies:
* ``pip install python-telegram-bot-raw[passport]`` installs the `cryptography>=3.0 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
* ``pip install python-telegram-bot-raw[socks]`` installs ``httpx[socks]``. Use this, if you want to work behind a Socks5 server.
* ``pip install python-telegram-bot-raw[passport]`` installs the `cryptography>=39.0.1 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
* ``pip install python-telegram-bot-raw[socks]`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
* ``pip install python-telegram-bot[http2]`` installs `httpx[http2] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to use HTTP/2.
To install multiple optional dependencies, separate them by commas, e.g. ``pip install python-telegram-bot-raw[passport,socks]``.
+2
View File
@@ -56,6 +56,8 @@ html:
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
rebuild: clean html
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
+591
View File
@@ -0,0 +1,591 @@
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2023
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
import collections.abc
import inspect
import re
import typing
from collections import defaultdict
from typing import Any, Iterator, Union
import telegram
import telegram.ext
def _iter_own_public_methods(cls: type) -> Iterator[tuple[str, type]]:
"""Iterates over methods of a class that are not protected/private,
not camelCase and not inherited from the parent class.
Returns pairs of method names and methods.
This function is defined outside the class because it is used to create class constants.
"""
return (
m
for m in inspect.getmembers(cls, predicate=inspect.isfunction) # not .ismethod
if not m[0].startswith("_")
and m[0].islower() # to avoid camelCase methods
and m[0] in cls.__dict__ # method is not inherited from parent class
)
class AdmonitionInserter:
"""Class for inserting admonitions into docs of Telegram classes."""
CLASS_ADMONITION_TYPES = ("use_in", "available_in", "returned_in")
METHOD_ADMONITION_TYPES = ("shortcuts",)
ALL_ADMONITION_TYPES = CLASS_ADMONITION_TYPES + METHOD_ADMONITION_TYPES
FORWARD_REF_PATTERN = re.compile(r"^ForwardRef\('(?P<class_name>\w+)'\)$")
""" A pattern to find a class name in a ForwardRef typing annotation.
Class name (in a named group) is surrounded by parentheses and single quotes.
Note that since we're analyzing argument by argument, the pattern can be strict, with
start and end markers.
"""
FORWARD_REF_SKIP_PATTERN = re.compile(r"^ForwardRef\('DefaultValue\[\w+]'\)$")
"""A pattern that will be used to skip known ForwardRef's that need not be resolved
to a Telegram class, e.g.:
ForwardRef('DefaultValue[None]')
ForwardRef('DefaultValue[DVValueType]')
"""
METHOD_NAMES_FOR_BOT_AND_APPBUILDER: dict[type, str] = {
cls: tuple(m[0] for m in _iter_own_public_methods(cls)) # m[0] means we take only names
for cls in (telegram.Bot, telegram.ext.ApplicationBuilder)
}
"""A dictionary mapping Bot and ApplicationBuilder classes to their relevant methods that will
be mentioned in 'Returned in' and 'Use in' admonitions in other classes' docstrings.
Methods must be public, not aliases, not inherited from TelegramObject.
"""
def __init__(self):
self.admonitions: dict[str, dict[Union[type, collections.abc.Callable], str]] = {
# dynamically determine which method to use to create a sub-dictionary
admonition_type: getattr(self, f"_create_{admonition_type}")()
for admonition_type in self.ALL_ADMONITION_TYPES
}
"""Dictionary with admonitions. Contains sub-dictionaries, one per admonition type.
Each sub-dictionary matches bot methods (for "Shortcuts") or telegram classes (for other
admonition types) to texts of admonitions, e.g.:
```
{
"use_in": {<class 'telegram._chatinvitelink.ChatInviteLink'>:
<"Use in" admonition for ChatInviteLink>, ...},
"available_in": {<class 'telegram._chatinvitelink.ChatInviteLink'>:
<"Available in" admonition">, ...},
"returned_in": {...}
}
```
"""
def insert_admonitions(
self,
obj: Union[type, collections.abc.Callable],
docstring_lines: list[str],
):
"""Inserts admonitions into docstring lines for a given class or method.
**Modifies lines in place**.
"""
# A better way would be to copy the lines and return them, but that will not work with
# docs.auxil.sphinx_hooks.autodoc_process_docstring()
for admonition_type in self.ALL_ADMONITION_TYPES:
# If there is no admonition of the given type for the given class or method,
# continue to the next admonition type, maybe the class/method is listed there.
if obj not in self.admonitions[admonition_type]:
continue
insert_idx = self._find_insert_pos_for_admonition(docstring_lines)
admonition_lines = self.admonitions[admonition_type][obj].splitlines()
for idx in range(insert_idx, insert_idx + len(admonition_lines)):
docstring_lines.insert(idx, admonition_lines[idx - insert_idx])
def _create_available_in(self) -> dict[type, str]:
"""Creates a dictionary with 'Available in' admonitions for classes that are available
in attributes of other classes.
"""
# Generate a mapping of classes to ReST links to attributes in other classes that
# correspond to instances of a given class
# i.e. {telegram._files.sticker.Sticker: {":attr:`telegram.Message.sticker`", ...}}
attrs_for_class = defaultdict(set)
# The following regex is supposed to capture a class name in a line like this:
# media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send.
#
# Note that even if such typing description spans over multiple lines but each line ends
# with a backslash (otherwise Sphinx will throw an error)
# (e.g. EncryptedPassportElement.data), then Sphinx will combine these lines into a single
# line automatically, and it will contain no backslash (only some extra many whitespaces
# from the indentation).
attr_docstr_pattern = re.compile(
r"^\s*(?P<attr_name>[a-z_]+)" # Any number of spaces, named group for attribute
r"\s?\(" # Optional whitespace, opening parenthesis
r".*" # Any number of characters (that could denote a built-in type)
r":class:`.+`" # Marker of a classref, class name in backticks
r".*\):" # Any number of characters, closing parenthesis, colon.
# The ^ colon above along with parenthesis is important because it makes sure that
# the class is mentioned in the attribute description, not in free text.
r".*$", # Any number of characters, end of string (end of line)
re.VERBOSE,
)
# for properties: there is no attr name in docstring. Just check if there's a class name.
prop_docstring_pattern = re.compile(r":class:`.+`.*:")
# pattern for iterating over potentially many class names in docstring for one attribute.
# Tilde is optional (sometimes it is in the docstring, sometimes not).
single_class_name_pattern = re.compile(r":class:`~?(?P<class_name>[\w.]*)`")
classes_to_inspect = inspect.getmembers(telegram, inspect.isclass) + inspect.getmembers(
telegram.ext, inspect.isclass
)
for class_name, inspected_class in classes_to_inspect:
# We need to make "<class 'telegram._files.sticker.StickerSet'>" into
# "telegram.StickerSet" because that's the way the classes are mentioned in
# docstrings.
name_of_inspected_class_in_docstr = self._generate_class_name_for_link(inspected_class)
# Parsing part of the docstring with attributes (parsing of properties follows later)
docstring_lines = inspect.getdoc(inspected_class).splitlines()
lines_with_attrs = []
for idx, line in enumerate(docstring_lines):
if line.strip() == "Attributes:":
lines_with_attrs = docstring_lines[idx + 1 :]
break
for line in lines_with_attrs:
line_match = attr_docstr_pattern.match(line)
if not line_match:
continue
target_attr = line_match.group("attr_name")
# a typing description of one attribute can contain multiple classes
for match in single_class_name_pattern.finditer(line):
name_of_class_in_attr = match.group("class_name")
# Writing to dictionary: matching the class found in the docstring
# and its subclasses to the attribute of the class being inspected.
# The class in the attribute docstring (or its subclass) is the key,
# ReST link to attribute of the class currently being inspected is the value.
try:
self._resolve_arg_and_add_link(
arg=name_of_class_in_attr,
dict_of_methods_for_class=attrs_for_class,
link=f":attr:`{name_of_inspected_class_in_docstr}.{target_attr}`",
)
except NotImplementedError as e:
raise NotImplementedError(
f"Error generating Sphinx 'Available in' admonition "
f"(admonition_inserter.py). Class {name_of_class_in_attr} present in "
f"attribute {target_attr} of class {name_of_inspected_class_in_docstr}"
f" could not be resolved. {str(e)}"
)
# Properties need to be parsed separately because they act like attributes but not
# listed as attributes.
properties = inspect.getmembers(inspected_class, lambda o: isinstance(o, property))
for prop_name, _ in properties:
# Make sure this property is really defined in the class being inspected.
# A property can be inherited from a parent class, then a link to it will not work.
if prop_name not in inspected_class.__dict__:
continue
# 1. Can't use typing.get_type_hints because double-quoted type hints
# (like "Application") will throw a NameError
# 2. Can't use inspect.signature because return annotations of properties can be
# hard to parse (like "(self) -> BD").
# 3. fget is used to access the actual function under the property wrapper
docstring = inspect.getdoc(getattr(inspected_class, prop_name).fget)
if docstring is None:
continue
first_line = docstring.splitlines()[0]
if not prop_docstring_pattern.match(first_line):
continue
for match in single_class_name_pattern.finditer(first_line):
name_of_class_in_prop = match.group("class_name")
# Writing to dictionary: matching the class found in the docstring and its
# subclasses to the property of the class being inspected.
# The class in the property docstring (or its subclass) is the key,
# ReST link to property of the class currently being inspected is the value.
try:
self._resolve_arg_and_add_link(
arg=name_of_class_in_prop,
dict_of_methods_for_class=attrs_for_class,
link=f":attr:`{name_of_inspected_class_in_docstr}.{prop_name}`",
)
except NotImplementedError as e:
raise NotImplementedError(
f"Error generating Sphinx 'Available in' admonition "
f"(admonition_inserter.py). Class {name_of_class_in_prop} present in "
f"property {prop_name} of class {name_of_inspected_class_in_docstr}"
f" could not be resolved. {str(e)}"
)
return self._generate_admonitions(attrs_for_class, admonition_type="available_in")
def _create_returned_in(self) -> dict[type, str]:
"""Creates a dictionary with 'Returned in' admonitions for classes that are returned
in Bot's and ApplicationBuilder's methods.
"""
# Generate a mapping of classes to ReST links to Bot methods which return it,
# i.e. {<class 'telegram._message.Message'>: {:meth:`telegram.Bot.send_message`, ...}}
methods_for_class = defaultdict(set)
for cls, method_names in self.METHOD_NAMES_FOR_BOT_AND_APPBUILDER.items():
for method_name in method_names:
sig = inspect.signature(getattr(cls, method_name))
ret_annot = sig.return_annotation
method_link = self._generate_link_to_method(method_name, cls)
try:
self._resolve_arg_and_add_link(
arg=ret_annot,
dict_of_methods_for_class=methods_for_class,
link=method_link,
)
except NotImplementedError as e:
raise NotImplementedError(
f"Error generating Sphinx 'Returned in' admonition "
f"(admonition_inserter.py). {cls}, method {method_name}. "
f"Couldn't resolve type hint in return annotation {ret_annot}. {str(e)}"
)
return self._generate_admonitions(methods_for_class, admonition_type="returned_in")
def _create_shortcuts(self) -> dict[collections.abc.Callable, str]:
"""Creates a dictionary with 'Shortcuts' admonitions for Bot methods that
have shortcuts in other classes.
"""
# pattern for looking for calls to Bot methods only
bot_method_pattern = re.compile(
r"""\s* # any number of whitespaces
(?<=return\sawait\sself\.get_bot\(\)\.) # lookbehind
\w+ # the method name we are looking for, letters/underscores
(?=\() # lookahead: opening bracket before the args of the method start
""",
re.VERBOSE,
)
# Generate a mapping of methods of classes to links to Bot methods which they are shortcuts
# for, i.e. {<function Bot.send_voice at ...>: {:meth:`telegram.User.send_voice`, ...}
shortcuts_for_bot_method = defaultdict(set)
# inspect methods of all telegram classes for return statements that indicate
# that this given method is a shortcut for a Bot method
for class_name, cls in inspect.getmembers(telegram, predicate=inspect.isclass):
# no need to inspect Bot's own methods, as Bot can't have shortcuts in Bot
if cls is telegram.Bot:
continue
for method_name, method in _iter_own_public_methods(cls):
# .getsourcelines() returns a tuple. Item [1] is an int
for line in inspect.getsourcelines(method)[0]:
if not (bot_method_match := bot_method_pattern.search(line)):
continue
bot_method = getattr(telegram.Bot, bot_method_match.group())
link_to_shortcut_method = self._generate_link_to_method(method_name, cls)
shortcuts_for_bot_method[bot_method].add(link_to_shortcut_method)
return self._generate_admonitions(shortcuts_for_bot_method, admonition_type="shortcuts")
def _create_use_in(self) -> dict[type, str]:
"""Creates a dictionary with 'Use in' admonitions for classes whose instances are
accepted as arguments for Bot's and ApplicationBuilder's methods.
"""
# Generate a mapping of classes to links to Bot methods which accept them as arguments,
# i.e. {<class 'telegram._inline.inlinequeryresult.InlineQueryResult'>:
# {:meth:`telegram.Bot.answer_inline_query`, ...}}
methods_for_class = defaultdict(set)
for cls, method_names in self.METHOD_NAMES_FOR_BOT_AND_APPBUILDER.items():
for method_name in method_names:
method_link = self._generate_link_to_method(method_name, cls)
sig = inspect.signature(getattr(cls, method_name))
parameters = sig.parameters
for param in parameters.values():
try:
self._resolve_arg_and_add_link(
arg=param.annotation,
dict_of_methods_for_class=methods_for_class,
link=method_link,
)
except NotImplementedError as e:
raise NotImplementedError(
f"Error generating Sphinx 'Use in' admonition "
f"(admonition_inserter.py). {cls}, method {method_name}, parameter "
f"{param}: Couldn't resolve type hint {param.annotation}. {str(e)}"
)
return self._generate_admonitions(methods_for_class, admonition_type="use_in")
@staticmethod
def _find_insert_pos_for_admonition(lines: list[str]) -> int:
"""Finds the correct position to insert the class admonition and returns the index.
The admonition will be insert above "See also", "Examples:", version added/changed notes
and args, whatever comes first.
If no key phrases are found, the admonition will be inserted at the very end.
"""
for idx, value in list(enumerate(lines)):
if (
value.startswith(".. seealso:")
# The docstring contains heading "Examples:", but Sphinx will have it converted
# to ".. admonition: Examples":
or value.startswith(".. admonition:: Examples")
or value.startswith(".. version")
# The space after ":param" is important because docstring can contain ":paramref:"
# in its plain text in the beginning of a line (e.g. ExtBot):
or value.startswith(":param ")
# some classes (like "Credentials") have no params, so insert before attrs:
or value.startswith(".. attribute::")
):
return idx
return len(lines) - 1
def _generate_admonitions(
self,
attrs_or_methods_for_class: dict[type, set[str]],
admonition_type: str,
) -> dict[type, str]:
"""Generates admonitions of a given type.
Takes a dictionary of classes matched to ReST links to methods or attributes, e.g.:
```
{<class 'telegram._files.sticker.StickerSet'>:
[":meth: `telegram.Bot.get_sticker_set`", ...]}.
```
Returns a dictionary of classes matched to full admonitions, e.g.
for `admonition_type` "returned_in" (note that title and CSS class are generated
automatically):
```
{<class 'telegram._files.sticker.StickerSet'>:
".. admonition:: Returned in:
:class: returned-in
:meth: `telegram.Bot.get_sticker_set`"}.
```
"""
if admonition_type not in self.ALL_ADMONITION_TYPES:
raise TypeError(f"Admonition type {admonition_type} not supported.")
admonition_for_class = {}
for cls, attrs in attrs_or_methods_for_class.items():
if cls is telegram.ext.ApplicationBuilder:
# ApplicationBuilder is only used in and returned from its own methods,
# so its page needs no admonitions.
continue
attrs = sorted(attrs)
# e.g. for admonition type "use_in" the title will be "Use in" and CSS class "use-in".
admonition = f"""
.. admonition:: {admonition_type.title().replace("_", " ")}
:class: {admonition_type.replace("_", "-")}
"""
if len(attrs) > 1:
for target_attr in attrs:
admonition += "\n * " + target_attr
else:
admonition += f"\n {attrs[0]}"
admonition += "\n " # otherwise an unexpected unindent warning will be issued
admonition_for_class[cls] = admonition
return admonition_for_class
@staticmethod
def _generate_class_name_for_link(cls: type) -> str:
"""Generates class name that can be used in a ReST link."""
# Check for potential presence of ".ext.", we will need to keep it.
ext = ".ext" if ".ext." in str(cls) else ""
return f"telegram{ext}.{cls.__name__}"
def _generate_link_to_method(self, method_name: str, cls: type) -> str:
"""Generates a ReST link to a method of a telegram class."""
return f":meth:`{self._generate_class_name_for_link(cls)}.{method_name}`"
@staticmethod
def _iter_subclasses(cls: type) -> Iterator:
return (
# exclude private classes
c
for c in cls.__subclasses__()
if not str(c).split(".")[-1].startswith("_")
)
def _resolve_arg_and_add_link(
self,
arg: Any,
dict_of_methods_for_class: defaultdict,
link: str,
) -> None:
"""A helper method. Tries to resolve the arg into a valid class. In case of success,
adds the link (to a method, attribute, or property) for that class' and its subclasses'
sets of links in the dictionary of admonitions.
**Modifies dictionary in place.**
"""
for cls in self._resolve_arg(arg):
# When trying to resolve an argument from args or return annotation,
# the method _resolve_arg returns None if nothing could be resolved.
# Also, if class was resolved correctly, "telegram" will definitely be in its str().
if cls is None or "telegram" not in str(cls):
continue
dict_of_methods_for_class[cls].add(link)
for subclass in self._iter_subclasses(cls):
dict_of_methods_for_class[subclass].add(link)
def _resolve_arg(self, arg: Any) -> Iterator[Union[type, None]]:
"""Analyzes an argument of a method and recursively yields classes that the argument
or its sub-arguments (in cases like Union[...]) belong to, if they can be resolved to
telegram or telegram.ext classes.
Raises `NotImplementedError`.
"""
origin = typing.get_origin(arg)
if (
origin in (collections.abc.Callable, typing.IO)
or arg is None
# no other check available (by type or origin) for these:
or str(type(arg)) in ("<class 'typing._SpecialForm'>", "<class 'ellipsis'>")
):
pass
# RECURSIVE CALLS
# for cases like Union[Sequence....
elif origin in (
Union,
collections.abc.Coroutine,
collections.abc.Sequence,
):
for sub_arg in typing.get_args(arg):
yield from self._resolve_arg(sub_arg)
elif isinstance(arg, typing.TypeVar):
# gets access to the "bound=..." parameter
yield from self._resolve_arg(arg.__bound__)
# END RECURSIVE CALLS
elif isinstance(arg, typing.ForwardRef):
m = self.FORWARD_REF_PATTERN.match(str(arg))
# We're sure it's a ForwardRef, so, unless it belongs to known exceptions,
# the class must be resolved.
# If it isn't resolved, we'll have the program throw an exception to be sure.
try:
cls = self._resolve_class(m.group("class_name"))
except AttributeError:
# skip known ForwardRef's that need not be resolved to a Telegram class
if self.FORWARD_REF_SKIP_PATTERN.match(str(arg)):
pass
else:
raise NotImplementedError(f"Could not process ForwardRef: {arg}")
else:
yield cls
# For custom generics like telegram.ext._application.Application[~BT, ~CCT, ~UD...].
# This must come before the check for isinstance(type) because GenericAlias can also be
# recognized as type if it belongs to <class 'types.GenericAlias'>.
elif str(type(arg)) in ("<class 'typing._GenericAlias'>", "<class 'types.GenericAlias'>"):
if "telegram" in str(arg):
# get_origin() of telegram.ext._application.Application[~BT, ~CCT, ~UD...]
# will produce <class 'telegram.ext._application.Application'>
yield origin
elif isinstance(arg, type):
if "telegram" in str(arg):
yield arg
# For some reason "InlineQueryResult", "InputMedia" & some others are currently not
# recognized as ForwardRefs and are identified as plain strings.
elif isinstance(arg, str):
# args like "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]" can be recognized as strings.
# Remove whatever is in the square brackets because it doesn't need to be parsed.
arg = re.sub(r"\[.+]", "", arg)
cls = self._resolve_class(arg)
# Here we don't want an exception to be thrown since we're not sure it's ForwardRef
if cls is not None:
yield cls
else:
raise NotImplementedError(
f"Cannot process argument {arg} of type {type(arg)} (origin {origin})"
)
@staticmethod
def _resolve_class(name: str) -> Union[type, None]:
"""The keys in the admonitions dictionary are not strings like "telegram.StickerSet"
but classes like <class 'telegram._files.sticker.StickerSet'>.
This method attempts to resolve a PTB class from a name that does or does not
contain the word 'telegram', e.g.
<class 'telegram._files.sticker.StickerSet'> from "telegram.StickerSet" or "StickerSet".
Returns a class on success, :obj:`None` if nothing could be resolved.
"""
for option in (
name,
f"telegram.{name}",
f"telegram.ext.{name}",
f"telegram.ext.filters.{name}",
):
try:
return eval(option)
# NameError will be raised if trying to eval just name and it doesn't work, e.g.
# "Name 'ApplicationBuilder' is not defined".
# AttributeError will be raised if trying to e.g. eval f"telegram.{name}" when the
# class denoted by `name` actually belongs to `telegram.ext`:
# "module 'telegram' has no attribute 'ApplicationBuilder'".
# If neither option works, this is not a PTB class.
except (NameError, AttributeError):
continue
if __name__ == "__main__":
# just try instantiating for debugging purposes
AdmonitionInserter()
+79
View File
@@ -0,0 +1,79 @@
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2023
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
import inspect
keyword_args = [
":keyword _sphinx_paramlinks_telegram.Bot.{method}.read_timeout: Value to pass to "
":paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to {read_timeout}.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.read_timeout: {read_timeout_type}, optional",
":keyword _sphinx_paramlinks_telegram.Bot.{method}.write_timeout: Value to pass to "
":paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to {write_timeout}.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.write_timeout: :obj:`float` | :obj:`None`, "
"optional",
":keyword _sphinx_paramlinks_telegram.Bot.{method}.connect_timeout: Value to pass to "
":paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to "
":attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.connect_timeout: :obj:`float` | "
":obj:`None`, optional",
":keyword _sphinx_paramlinks_telegram.Bot.{method}.pool_timeout: Value to pass to "
":paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to "
":attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.pool_timeout: :obj:`float` | :obj:`None`, "
"optional",
":keyword _sphinx_paramlinks_telegram.Bot.{method}.api_kwargs: Arbitrary keyword arguments "
"to be passed to the Telegram API.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.api_kwargs: :obj:`dict`, optional",
"",
]
write_timeout_sub = [":attr:`~telegram.request.BaseRequest.DEFAULT_NONE`", "``20``"]
read_timeout_sub = [
":attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.",
"``2``. :paramref:`timeout` will be added to this value",
]
read_timeout_type = [":obj:`float` | :obj:`None`", ":obj:`float`"]
def find_insert_pos_for_kwargs(lines: list[str]) -> int:
"""Finds the correct position to insert the keyword arguments and returns the index."""
for idx, value in reversed(list(enumerate(lines))): # reversed since :returns: is at the end
if value.startswith(":returns:"):
return idx
else:
return False
def is_write_timeout_20(obj: object) -> int:
"""inspects the default value of write_timeout parameter of the bot method."""
sig = inspect.signature(obj)
return 1 if (sig.parameters["write_timeout"].default == 20) else 0
def check_timeout_and_api_kwargs_presence(obj: object) -> int:
"""Checks if the method has timeout and api_kwargs keyword only parameters."""
sig = inspect.signature(obj)
params_to_check = (
"read_timeout",
"write_timeout",
"connect_timeout",
"pool_timeout",
"api_kwargs",
)
return all(
param in sig.parameters and sig.parameters[param].kind == inspect.Parameter.KEYWORD_ONLY
for param in params_to_check
)
+77
View File
@@ -0,0 +1,77 @@
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2023
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Functionality in this file is used for getting the [source] links on the classes, methods etc
to link to the correct files & lines on github. Can be simplified once
https://github.com/sphinx-doc/sphinx/issues/1556 is closed
"""
import subprocess
from sphinx.util import logging
# get the sphinx(!) logger
# Makes sure logs render in red and also plays nicely with e.g. the `nitpicky` option.
sphinx_logger = logging.getLogger(__name__)
# must be a module-level variable so that it can be written to by the `autodoc-process-docstring`
# event handler in `sphinx_hooks.py`
LINE_NUMBERS = {}
def _git_branch() -> str:
"""Get's the current git sha if available or fall back to `master`"""
try:
output = subprocess.check_output( # skipcq: BAN-B607
["git", "describe", "--tags", "--always"], stderr=subprocess.STDOUT
)
return output.decode().strip()
except Exception as exc:
sphinx_logger.exception(
"Failed to get a description of the current commit. Falling back to `master`.",
exc_info=exc,
)
return "master"
git_branch = _git_branch()
base_url = "https://github.com/python-telegram-bot/python-telegram-bot/blob/"
def linkcode_resolve(_, info):
"""See www.sphinx-doc.org/en/master/usage/extensions/linkcode.html"""
combined = ".".join((info["module"], info["fullname"]))
# special casing for ExtBot which is due to the special structure of extbot.rst
combined = combined.replace("ExtBot.ExtBot", "ExtBot")
line_info = LINE_NUMBERS.get(combined)
if not line_info:
# Try the __init__
line_info = LINE_NUMBERS.get(f"{combined.rsplit('.', 1)[0]}.__init__")
if not line_info:
# Try the class
line_info = LINE_NUMBERS.get(f"{combined.rsplit('.', 1)[0]}")
if not line_info:
# Try the module
line_info = LINE_NUMBERS.get(info["module"])
if not line_info:
return
file, start_line, end_line = line_info
return f"{base_url}{git_branch}/{file}#L{start_line}-L{end_line}"
+209
View File
@@ -0,0 +1,209 @@
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2023
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
import collections.abc
import inspect
import re
import typing
from pathlib import Path
from sphinx.application import Sphinx
import telegram
import telegram.ext
from docs.auxil.admonition_inserter import AdmonitionInserter
from docs.auxil.kwargs_insertion import (
check_timeout_and_api_kwargs_presence,
find_insert_pos_for_kwargs,
is_write_timeout_20,
keyword_args,
read_timeout_sub,
read_timeout_type,
write_timeout_sub,
)
from docs.auxil.link_code import LINE_NUMBERS
ADMONITION_INSERTER = AdmonitionInserter()
# Some base classes are implementation detail
# We want to instead show *their* base class
PRIVATE_BASE_CLASSES = {
"_ChatUserBaseFilter": "MessageFilter",
"_Dice": "MessageFilter",
"_BaseThumbedMedium": "TelegramObject",
"_BaseMedium": "TelegramObject",
"_CredentialsBase": "TelegramObject",
}
FILE_ROOT = Path(inspect.getsourcefile(telegram)).parent.parent.resolve()
def autodoc_skip_member(app, what, name, obj, skip, options):
"""We use this to not document certain members like filter() or check_update() for filters.
See https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#skipping-members"""
included = {"MessageFilter", "UpdateFilter"} # filter() and check_update() only for these.
included_in_obj = any(inc in repr(obj) for inc in included)
if included_in_obj: # it's difficult to see if check_update is from an inherited-member or not
for frame in inspect.stack(): # From https://github.com/sphinx-doc/sphinx/issues/9533
if frame.function == "filter_members":
docobj = frame.frame.f_locals["self"].object
if not any(inc in str(docobj) for inc in included) and name == "check_update":
return True
break
if name == "filter" and obj.__module__ == "telegram.ext.filters":
if not included_in_obj:
return True # return True to exclude from docs.
def autodoc_process_docstring(
app: Sphinx, what, name: str, obj: object, options, lines: list[str]
):
"""We do the following things:
1) Use this method to automatically insert the Keyword Args and "Shortcuts" admonitions
for the Bot methods.
2) Use this method to automatically insert "Returned in" admonition into classes
that are returned from the Bot methods
3) Use this method to automatically insert "Available in" admonition into classes
whose instances are available as attributes of other classes
4) Use this method to automatically insert "Use in" admonition into classes
whose instances can be used as arguments of the Bot methods
5) Misuse this autodoc hook to get the file names & line numbers because we have access
to the actual object here.
"""
# 1) Insert the Keyword Args and "Shortcuts" admonitions for the Bot methods
method_name = name.split(".")[-1]
if (
name.startswith("telegram.Bot.")
and what == "method"
and method_name.islower()
and check_timeout_and_api_kwargs_presence(obj)
):
insert_index = find_insert_pos_for_kwargs(lines)
if not insert_index:
raise ValueError(
f"Couldn't find the correct position to insert the keyword args for {obj}."
)
long_write_timeout = is_write_timeout_20(obj)
get_updates_sub = 1 if (method_name == "get_updates") else 0
# The below can be done in 1 line with itertools.chain, but this must be modified in-place
for i in range(insert_index, insert_index + len(keyword_args)):
lines.insert(
i,
keyword_args[i - insert_index].format(
method=method_name,
write_timeout=write_timeout_sub[long_write_timeout],
read_timeout=read_timeout_sub[get_updates_sub],
read_timeout_type=read_timeout_type[get_updates_sub],
),
)
ADMONITION_INSERTER.insert_admonitions(
obj=typing.cast(collections.abc.Callable, obj),
docstring_lines=lines,
)
# 2-4) Insert "Returned in", "Available in", "Use in" admonitions into classes
# (where applicable)
if what == "class":
ADMONITION_INSERTER.insert_admonitions(
obj=typing.cast(type, obj), # since "what" == class, we know it's not just object
docstring_lines=lines,
)
# 5) Get the file names & line numbers
# We can't properly handle ordinary attributes.
# In linkcode_resolve we'll resolve to the `__init__` or module instead
if what == "attribute":
return
# Special casing for properties
if hasattr(obj, "fget"):
obj = obj.fget
# Special casing for filters
if isinstance(obj, telegram.ext.filters.BaseFilter):
obj = obj.__class__
try:
source_lines, start_line = inspect.getsourcelines(obj)
end_line = start_line + len(source_lines)
file = Path(inspect.getsourcefile(obj)).relative_to(FILE_ROOT)
LINE_NUMBERS[name] = (file, start_line, end_line)
except Exception:
pass
# Since we don't document the `__init__`, we call this manually to have it available for
# attributes -- see the note above
if what == "class":
autodoc_process_docstring(app, "method", f"{name}.__init__", obj.__init__, options, lines)
def autodoc_process_bases(app, name, obj, option, bases: list):
"""Here we fine tune how the base class's classes are displayed."""
for idx, base in enumerate(bases):
# let's use a string representation of the object
base = str(base)
# Special case for abstract context managers which are wrongly resoled for some reason
if base.startswith("typing.AbstractAsyncContextManager"):
bases[idx] = ":class:`contextlib.AbstractAsyncContextManager`"
continue
# Special case because base classes are in std lib:
if "StringEnum" in base == "<enum 'StringEnum'>":
bases[idx] = ":class:`enum.Enum`"
bases.insert(0, ":class:`str`")
continue
if "IntEnum" in base:
bases[idx] = ":class:`enum.IntEnum`"
continue
# Drop generics (at least for now)
if base.endswith("]"):
base = base.split("[", maxsplit=1)[0]
bases[idx] = f":class:`{base}`"
# Now convert `telegram._message.Message` to `telegram.Message` etc
match = re.search(pattern=r"(telegram(\.ext|))\.[_\w\.]+", string=base)
if not match or "_utils" in base:
continue
parts = match.group(0).split(".")
# Remove private paths
for index, part in enumerate(parts):
if part.startswith("_"):
parts = parts[:index] + parts[-1:]
break
# Replace private base classes with their respective parent
parts = [PRIVATE_BASE_CLASSES.get(part, part) for part in parts]
base = ".".join(parts)
bases[idx] = f":class:`{base}`"
+92
View File
@@ -0,0 +1,92 @@
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2023
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
from enum import Enum
from docutils.nodes import Element
from sphinx.domains.python import PyXRefRole
from sphinx.environment import BuildEnvironment
from sphinx.util import logging
import telegram
# get the sphinx(!) logger
# Makes sure logs render in red and also plays nicely with e.g. the `nitpicky` option.
sphinx_logger = logging.getLogger(__name__)
CONSTANTS_ROLE = "tg-const"
class TGConstXRefRole(PyXRefRole):
"""This is a bit of Sphinx magic. We add a new role type called tg-const that allows us to
reference values from the `telegram.constants.module` while using the actual value as title
of the link.
Example:
:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` renders as `4096` but links to
the constant.
"""
def process_link(
self,
env: BuildEnvironment,
refnode: Element,
has_explicit_title: bool,
title: str,
target: str,
) -> tuple[str, str]:
title, target = super().process_link(env, refnode, has_explicit_title, title, target)
try:
# We use `eval` to get the value of the expression. Maybe there are better ways to
# do this via importlib or so, but it does the job for now
value = eval(target)
# Maybe we need a better check if the target is actually from tg.constants
# for now checking if it's an Enum suffices since those are used nowhere else in PTB
if isinstance(value, Enum):
# Special casing for file size limits
if isinstance(value, telegram.constants.FileSizeLimit):
return f"{int(value.value / 1e6)} MB", target
return repr(value.value), target
# 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.",
refnode.source,
refnode.line,
refnode.rawsource,
)
return title, target
except Exception as exc:
sphinx_logger.exception(
"%s:%d: WARNING: Did not convert reference %s due to an exception.",
refnode.source,
refnode.line,
refnode.rawsource,
exc_info=exc,
)
return title, target
+5 -4
View File
@@ -1,6 +1,7 @@
sphinx==5.3.0
sphinx==6.1.3
sphinx-pypi-upload
furo==2022.12.7
git+https://github.com/harshil21/furo-sphinx-search@be5cfa221a01f6e259bb2bb1f76d6ede7ffc1f11#egg=furo-sphinx-search
furo==2023.3.23
git+https://github.com/harshil21/furo-sphinx-search@01efc7be422d7dc02390aab9be68d6f5ce1a5618#egg=furo-sphinx-search
sphinx-paramlinks==0.5.4
sphinxcontrib-mermaid==0.7.1
sphinxcontrib-mermaid==0.8.1
sphinx-copybutton==0.5.1
+65
View File
@@ -0,0 +1,65 @@
:root {
--icon--shortcuts: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-signpost' viewBox='0 0 16 16'%3E%3Cpath d='M7 1.414V4H2a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h5v6h2v-6h3.532a1 1 0 0 0 .768-.36l1.933-2.32a.5.5 0 0 0 0-.64L13.3 4.36a1 1 0 0 0-.768-.36H9V1.414a1 1 0 0 0-2 0zM12.532 5l1.666 2-1.666 2H2V5h10.532z'/%3E%3C/svg%3E");
--icon--returned-in: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-arrow-return-right' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M1.5 1.5A.5.5 0 0 0 1 2v4.8a2.5 2.5 0 0 0 2.5 2.5h9.793l-3.347 3.346a.5.5 0 0 0 .708.708l4.2-4.2a.5.5 0 0 0 0-.708l-4-4a.5.5 0 0 0-.708.708L13.293 8.3H3.5A1.5 1.5 0 0 1 2 6.8V2a.5.5 0 0 0-.5-.5z'/%3E%3C/svg%3E");
--icon--available-in: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-geo-fill' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4 4a4 4 0 1 1 4.5 3.969V13.5a.5.5 0 0 1-1 0V7.97A4 4 0 0 1 4 3.999zm2.493 8.574a.5.5 0 0 1-.411.575c-.712.118-1.28.295-1.655.493a1.319 1.319 0 0 0-.37.265.301.301 0 0 0-.057.09V14l.002.008a.147.147 0 0 0 .016.033.617.617 0 0 0 .145.15c.165.13.435.27.813.395.751.25 1.82.414 3.024.414s2.273-.163 3.024-.414c.378-.126.648-.265.813-.395a.619.619 0 0 0 .146-.15.148.148 0 0 0 .015-.033L12 14v-.004a.301.301 0 0 0-.057-.09 1.318 1.318 0 0 0-.37-.264c-.376-.198-.943-.375-1.655-.493a.5.5 0 1 1 .164-.986c.77.127 1.452.328 1.957.594C12.5 13 13 13.4 13 14c0 .426-.26.752-.544.977-.29.228-.68.413-1.116.558-.878.293-2.059.465-3.34.465-1.281 0-2.462-.172-3.34-.465-.436-.145-.826-.33-1.116-.558C3.26 14.752 3 14.426 3 14c0-.599.5-1 .961-1.243.505-.266 1.187-.467 1.957-.594a.5.5 0 0 1 .575.411z'/%3E%3C/svg%3E");
--icon--use-in:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-funnel' viewBox='0 0 16 16'%3E%3Cpath d='M1.5 1.5A.5.5 0 0 1 2 1h12a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.128.334L10 8.692V13.5a.5.5 0 0 1-.342.474l-3 1A.5.5 0 0 1 6 14.5V8.692L1.628 3.834A.5.5 0 0 1 1.5 3.5v-2zm1 .5v1.308l4.372 4.858A.5.5 0 0 1 7 8.5v5.306l2-.666V8.5a.5.5 0 0 1 .128-.334L13.5 3.308V2h-11z'/%3E%3C/svg%3E");
}
.admonition.shortcuts {
border-color: rgb(43, 155, 70);
}
.admonition.shortcuts > .admonition-title {
background-color: rgba(43, 155, 70, 0.1);
border-color: rgb(43, 155, 70);
}
.admonition.shortcuts > .admonition-title::before {
background-color: rgb(43, 155, 70);
-webkit-mask-image: var(--icon--shortcuts);
mask-image: var(--icon--shortcuts);
}
.admonition.returned-in {
border-color: rgb(230, 109, 15);
}
.admonition.returned-in > .admonition-title {
background-color: rgba(177, 108, 51, 0.1);
border-color: rgb(230, 109, 15);
}
.admonition.returned-in > .admonition-title::before {
background-color: rgb(230, 109, 15);
-webkit-mask-image: var(--icon--returned-in);
mask-image: var(--icon--returned-in);
}
.admonition.available-in {
border-color: rgb(183, 4, 215);
}
.admonition.available-in > .admonition-title {
background-color: rgba(165, 99, 177, 0.1);
border-color: rgb(183, 4, 215);
}
.admonition.available-in > .admonition-title::before {
background-color: rgb(183, 4, 215);
-webkit-mask-image: var(--icon--available-in);
mask-image: var(--icon--available-in);
}
.admonition.use-in {
border-color: rgb(203, 147, 1);
}
.admonition.use-in > .admonition-title {
background-color: rgba(176, 144, 60, 0.1);
border-color: rgb(203, 147, 1);
}
.admonition.use-in > .admonition-title::before {
background-color: rgb(203, 147, 1);
-webkit-mask-image: var(--icon--use-in);
mask-image: var(--icon--use-in);
}
.admonition.returned-in > ul:hover, .admonition.available-in > ul:hover, .admonition.use-in > ul:hover, .admonition.shortcuts > ul:hover {
cursor: move;
}
.admonition.returned-in > ul, .admonition.available-in > ul, .admonition.use-in > ul, .admonition.shortcuts > ul {
max-height: 200px;
overflow-y: scroll;
}
+3
View File
@@ -0,0 +1,3 @@
.article-container h1 {
overflow-wrap: anywhere;
}
+15
View File
@@ -0,0 +1,15 @@
figure > img {
height: 300px; /* resize figures so they aren't too big */
}
@media (prefers-color-scheme: dark) {
body:not([data-theme="light"]) figure > img { /* auto and dark is dark mode */
filter: invert(92%);
}
}
@media (prefers-color-scheme: light) {
body[data-theme="dark"] figure > img { /* auto and light is light mode */
filter: invert(92%);
}
}
@@ -0,0 +1,11 @@
.sidebar-sticky .sidebar-brand {
flex-direction: row;
}
.sidebar-sticky .sidebar-brand .sidebar-logo-container {
align-self: center;
}
.sidebar-sticky .sidebar-brand .sidebar-brand-text {
align-self: center;
}
+26 -327
View File
@@ -1,27 +1,19 @@
import inspect
import os
import re
import subprocess
import sys
from enum import Enum
from pathlib import Path
from typing import List, Tuple
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
from docutils.nodes import Element
from sphinx.application import Sphinx
from sphinx.domains.python import PyXRefRole
from sphinx.environment import BuildEnvironment
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"
copyright = "2015-2023, Leandro Toledo"
author = "Leandro Toledo"
# The version info for the project you're documenting, acts as replacement for
@@ -29,12 +21,12 @@ author = "Leandro Toledo"
# built documents.
#
# The short X.Y version.
version = "20.0b0" # telegram.__version__[:3]
version = "20.2" # telegram.__version__[:3]
# The full version, including alpha/beta/rc tags.
release = "20.0b0" # telegram.__version__
release = "20.2" # telegram.__version__
# If your documentation needs a minimal Sphinx version, state it here.
needs_sphinx = "5.1.1"
needs_sphinx = "6.1.3"
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
@@ -44,11 +36,16 @@ extensions = [
"sphinx.ext.napoleon",
"sphinx.ext.intersphinx",
"sphinx.ext.linkcode",
"sphinx.ext.extlinks",
"sphinx_paramlinks",
"sphinx_copybutton",
"sphinxcontrib.mermaid",
"sphinx_search.extension",
]
# For shorter links to Wiki in docstrings
extlinks = {"wiki": ("https://github.com/python-telegram-bot/python-telegram-bot/wiki/%s", "%s")}
# Use intersphinx to reference the python builtin library docs
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
@@ -216,7 +213,14 @@ html_favicon = "ptb-logo_1024.ico"
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
html_css_files = ["style_external_link.css", "style_mermaid_diagrams.css"]
html_css_files = [
"style_external_link.css",
"style_mermaid_diagrams.css",
"style_sidebar_brand.css",
"style_general.css",
"style_admonitions.css",
"style_images.css",
]
html_permalinks_icon = "" # Furo's default permalink icon is `#` which doesn't look great imo.
@@ -280,321 +284,16 @@ texinfo_documents = [
# -- script stuff --------------------------------------------------------
# get the sphinx(!) logger
# Makes sure logs render in red and also plays nicely with e.g. the `nitpicky` option.
sphinx_logger = logging.getLogger(__name__)
# Due to Sphinx behaviour, these imports only work when imported here, not at top of module.
CONSTANTS_ROLE = "tg-const"
import telegram # We need this so that the `eval` below works
class TGConstXRefRole(PyXRefRole):
"""This is a bit of Sphinx magic. We add a new role type called tg-const that allows us to
reference values from the `telegram.constants.module` while using the actual value as title
of the link.
Example:
:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` renders as `4096` but links to the
constant.
"""
def process_link(
self,
env: BuildEnvironment,
refnode: Element,
has_explicit_title: bool,
title: str,
target: str,
) -> Tuple[str, str]:
title, target = super().process_link(env, refnode, has_explicit_title, title, target)
try:
# We use `eval` to get the value of the expression. Maybe there are better ways to
# do this via importlib or so, but it does the job for now
value = eval(target)
# Maybe we need a better check if the target is actually from tg.constants
# for now checking if it's an Enum suffices since those are used nowhere else in PTB
if isinstance(value, Enum):
# Special casing for file size limits
if isinstance(value, telegram.constants.FileSizeLimit):
return f"{int(value.value / 1e6)} MB", target
return repr(value.value), target
# 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.",
refnode.source,
refnode.line,
refnode.rawsource,
)
return title, target
except Exception as exc:
sphinx_logger.exception(
f"%s:%d: WARNING: Did not convert reference %s due to an exception.",
refnode.source,
refnode.line,
refnode.rawsource,
exc_info=exc,
)
return title, target
def autodoc_skip_member(app, what, name, obj, skip, options):
"""We use this to not document certain members like filter() or check_update() for filters.
See https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#skipping-members"""
included = {"MessageFilter", "UpdateFilter"} # filter() and check_update() only for these.
included_in_obj = any(inc in repr(obj) for inc in included)
if included_in_obj: # it's difficult to see if check_update is from an inherited-member or not
for frame in inspect.stack(): # From https://github.com/sphinx-doc/sphinx/issues/9533
if frame.function == "filter_members":
docobj = frame.frame.f_locals["self"].object
if not any(inc in str(docobj) for inc in included) and name == "check_update":
return True
break
if name == "filter" and obj.__module__ == "telegram.ext.filters":
if not included_in_obj:
return True # return True to exclude from docs.
# ------------------------------------------------------------------------------------------------
# This part is for getting the [source] links on the classes, methods etc link to the correct
# files & lines on github. Can be simplified once https://github.com/sphinx-doc/sphinx/issues/1556
# is closed
line_numbers = {}
file_root = Path(inspect.getsourcefile(telegram)).parent.parent.resolve()
import telegram.ext # Needed for checking if an object is a BaseFilter
keyword_args = [
":keyword _sphinx_paramlinks_telegram.Bot.{method}.read_timeout: Value to pass to :paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to {read_timeout}.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.read_timeout: {read_timeout_type}, optional",
":keyword _sphinx_paramlinks_telegram.Bot.{method}.write_timeout: Value to pass to :paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to {write_timeout}.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.write_timeout: :obj:`float` | :obj:`None`, optional",
":keyword _sphinx_paramlinks_telegram.Bot.{method}.connect_timeout: Value to pass to :paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.connect_timeout: :obj:`float` | :obj:`None`, optional",
":keyword _sphinx_paramlinks_telegram.Bot.{method}.pool_timeout: Value to pass to :paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.pool_timeout: :obj:`float` | :obj:`None`, optional",
":keyword _sphinx_paramlinks_telegram.Bot.{method}.api_kwargs: Arbitrary keyword arguments to be passed to the Telegram API.",
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.api_kwargs: :obj:`dict`, optional",
"",
]
write_timeout_sub = [":attr:`~telegram.request.BaseRequest.DEFAULT_NONE`", "``20``"]
read_timeout_sub = [
":attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.",
"``2``. :paramref:`timeout` will be added to this value",
]
read_timeout_type = [":obj:`float` | :obj:`None`", ":obj:`float`"]
def find_insert_pos(lines: List[str]) -> int:
"""Finds the correct position to insert the keyword arguments and returns the index."""
for idx, value in reversed(list(enumerate(lines))): # reversed since :returns: is at the end
if value.startswith(":returns:"):
return idx
else:
return False
def is_write_timeout_20(obj: object) -> int:
"""inspects the default value of write_timeout parameter of the bot method."""
sig = inspect.signature(obj)
return 1 if (sig.parameters["write_timeout"].default == 20) else 0
def check_timeout_and_api_kwargs_presence(obj: object) -> int:
"""Checks if the method has timeout and api_kwargs keyword only parameters."""
sig = inspect.signature(obj)
params_to_check = (
"read_timeout",
"write_timeout",
"connect_timeout",
"pool_timeout",
"api_kwargs",
)
return all(
param in sig.parameters and sig.parameters[param].kind == inspect.Parameter.KEYWORD_ONLY
for param in params_to_check
)
def autodoc_process_docstring(
app: Sphinx, what, name: str, obj: object, options, lines: List[str]
):
"""We do two things:
1) Use this method to automatically insert the Keyword Args for the Bot methods.
2) Misuse this autodoc hook to get the file names & line numbers because we have access
to the actual object here.
"""
# 1) Insert the Keyword Args for the Bot methods
method_name = name.split(".")[-1]
if (
name.startswith("telegram.Bot.")
and what == "method"
and method_name.islower()
and check_timeout_and_api_kwargs_presence(obj)
):
insert_index = find_insert_pos(lines)
if not insert_index:
raise ValueError(
f"Couldn't find the correct position to insert the keyword args for {obj}."
)
long_write_timeout = is_write_timeout_20(obj)
get_updates_sub = 1 if (method_name == "get_updates") else 0
# The below can be done in 1 line with itertools.chain, but this must be modified in-place
for i in range(insert_index, insert_index + len(keyword_args)):
lines.insert(
i,
keyword_args[i - insert_index].format(
method=method_name,
write_timeout=write_timeout_sub[long_write_timeout],
read_timeout=read_timeout_sub[get_updates_sub],
read_timeout_type=read_timeout_type[get_updates_sub],
),
)
# 2) Get the file names & line numbers
# We can't properly handle ordinary attributes.
# In linkcode_resolve we'll resolve to the `__init__` or module instead
if what == "attribute":
return
# Special casing for properties
if hasattr(obj, "fget"):
obj = obj.fget
# Special casing for filters
if isinstance(obj, telegram.ext.filters.BaseFilter):
obj = obj.__class__
try:
source_lines, start_line = inspect.getsourcelines(obj)
end_line = start_line + len(source_lines)
file = Path(inspect.getsourcefile(obj)).relative_to(file_root)
line_numbers[name] = (file, start_line, end_line)
except Exception:
pass
# Since we don't document the `__init__`, we call this manually to have it available for
# attributes -- see the note above
if what == "class":
autodoc_process_docstring(app, "method", f"{name}.__init__", obj.__init__, options, lines)
def _git_branch() -> str:
"""Get's the current git sha if available or fall back to `master`"""
try:
output = subprocess.check_output( # skipcq: BAN-B607
["git", "describe", "--tags", "--always"], stderr=subprocess.STDOUT
)
return output.decode().strip()
except Exception as exc:
sphinx_logger.exception(
f"Failed to get a description of the current commit. Falling back to `master`.",
exc_info=exc,
)
return "master"
git_branch = _git_branch()
base_url = "https://github.com/python-telegram-bot/python-telegram-bot/blob/"
def linkcode_resolve(_, info):
"""See www.sphinx-doc.org/en/master/usage/extensions/linkcode.html"""
combined = ".".join((info["module"], info["fullname"]))
# special casing for ExtBot which is due to the special structure of extbot.rst
combined = combined.replace("ExtBot.ExtBot", "ExtBot")
line_info = line_numbers.get(combined)
if not line_info:
# Try the __init__
line_info = line_numbers.get(f"{combined.rsplit('.', 1)[0]}.__init__")
if not line_info:
# Try the class
line_info = line_numbers.get(f"{combined.rsplit('.', 1)[0]}")
if not line_info:
# Try the module
line_info = line_numbers.get(info["module"])
if not line_info:
return
file, start_line, end_line = line_info
return f"{base_url}{git_branch}/{file}#L{start_line}-L{end_line}"
# End of logic for the [source] links
# ------------------------------------------------------------------------------------------------
# Some base classes are implementation detail
# We want to instead show *their* base class
PRIVATE_BASE_CLASSES = {
"_ChatUserBaseFilter": "MessageFilter",
"_Dice": "MessageFilter",
"_BaseThumbedMedium": "TelegramObject",
"_BaseMedium": "TelegramObject",
"_CredentialsBase": "TelegramObject",
}
def autodoc_process_bases(app, name, obj, option, bases: list):
"""Here we fine tune how the base class's classes are displayed."""
for idx, base in enumerate(bases):
# let's use a string representation of the object
base = str(base)
# Special case because base classes are in std lib:
if "StringEnum" in base == "<enum 'StringEnum'>":
bases[idx] = ":class:`enum.Enum`"
bases.insert(0, ":class:`str`")
continue
if "IntEnum" in base:
bases[idx] = ":class:`enum.IntEnum`"
continue
# Drop generics (at least for now)
if base.endswith("]"):
base = base.split("[", maxsplit=1)[0]
bases[idx] = f":class:`{base}`"
# Now convert `telegram._message.Message` to `telegram.Message` etc
match = re.search(pattern=r"(telegram(\.ext|))\.[_\w\.]+", string=base)
if not match or "_utils" in base:
continue
parts = match.group(0).split(".")
# Remove private paths
for index, part in enumerate(parts):
if part.startswith("_"):
parts = parts[:index] + parts[-1:]
break
# Replace private base classes with their respective parent
parts = [PRIVATE_BASE_CLASSES.get(part, part) for part in parts]
base = ".".join(parts)
bases[idx] = f":class:`{base}`"
# Not used but must be imported for the linkcode extension to find it
from docs.auxil.link_code import linkcode_resolve
from docs.auxil.sphinx_hooks import (
autodoc_process_bases,
autodoc_process_docstring,
autodoc_skip_member,
)
from docs.auxil.tg_const_role import CONSTANTS_ROLE, TGConstXRefRole
def setup(app: Sphinx):
+51 -6
View File
@@ -157,6 +157,23 @@
- Used for getting the number of members in a chat
* - :meth:`~telegram.Bot.get_chat_member`
- Used for getting a member of a chat
* - :meth:`~telegram.Bot.leave_chat`
- Used for leaving a chat
.. raw:: html
</details>
<br>
.. raw:: html
<details>
<summary>Bot settings</summary>
.. list-table::
:align: left
:widths: 1 4
* - :meth:`~telegram.Bot.set_my_commands`
- Used for setting the list of commands
* - :meth:`~telegram.Bot.delete_my_commands`
@@ -171,8 +188,14 @@
- Used for obtaining the menu button of a private chat or the default menu button
* - :meth:`~telegram.Bot.set_chat_menu_button`
- Used for setting the menu button of a private chat or the default menu button
* - :meth:`~telegram.Bot.leave_chat`
- Used for leaving a chat
* - :meth:`~telegram.Bot.set_my_description`
- Used for setting the description of the bot
* - :meth:`~telegram.Bot.get_my_description`
- Used for obtaining the description of the bot
* - :meth:`~telegram.Bot.set_my_short_description`
- Used for setting the short description of the bot
* - :meth:`~telegram.Bot.get_my_short_description`
- Used for obtaining the short description of the bot
.. raw:: html
@@ -194,14 +217,26 @@
- Used for deleting a sticker from a set
* - :meth:`~telegram.Bot.create_new_sticker_set`
- Used for creating a new sticker set
* - :meth:`~telegram.Bot.delete_sticker_set`
- Used for deleting a sticker set made by a bot
* - :meth:`~telegram.Bot.set_chat_sticker_set`
- Used for setting a sticker set
- Used for setting a sticker set of a chat
* - :meth:`~telegram.Bot.delete_chat_sticker_set`
- Used for deleting the set sticker set
- Used for deleting the set sticker set of a chat
* - :meth:`~telegram.Bot.set_sticker_position_in_set`
- Used for moving a sticker's position in the set
* - :meth:`~telegram.Bot.set_sticker_set_title`
- Used for setting the title of a sticker set
* - :meth:`~telegram.Bot.set_sticker_emoji_list`
- Used for setting the emoji list of a sticker
* - :meth:`~telegram.Bot.set_sticker_keywords`
- Used for setting the keywords of a sticker
* - :meth:`~telegram.Bot.set_sticker_mask_position`
- Used for setting the mask position of a mask sticker
* - :meth:`~telegram.Bot.set_sticker_set_thumb`
- Used for setting the thumbnail of a sticker set
* - :meth:`~telegram.Bot.set_custom_emoji_sticker_set_thumbnail`
- Used for setting the thumbnail of a custom emoji sticker set
* - :meth:`~telegram.Bot.get_sticker_set`
- Used for getting a sticker set
* - :meth:`~telegram.Bot.upload_sticker_file`
@@ -267,16 +302,26 @@
* - :meth:`~telegram.Bot.close_forum_topic`
- Used for closing a forum topic
* - :meth:`~telegram.Bot.close_general_forum_topic`
- Used for closing the general forum topic
* - :meth:`~telegram.Bot.create_forum_topic`
- Used to create a topic
* - :meth:`~telegram.Bot.delete_forum_topic`
- Used for deleting a forum topic
* - :meth:`~telegram.Bot.edit_forum_topic`
- Used to edit a topic
* - :meth:`~telegram.Bot.reopen_forum_topic`
- Used to reopen a topic
* - :meth:`~telegram.Bot.edit_general_forum_topic`
- Used to edit the general topic
* - :meth:`~telegram.Bot.get_forum_topic_icon_stickers`
- Used to get custom emojis to use as topic icons
* - :meth:`~telegram.Bot.hide_general_forum_topic`
- Used to hide the general topic
* - :meth:`~telegram.Bot.unhide_general_forum_topic`
- Used to unhide the general topic
* - :meth:`~telegram.Bot.reopen_forum_topic`
- Used to reopen a topic
* - :meth:`~telegram.Bot.reopen_general_forum_topic`
- Used to reopen the general topic
* - :meth:`~telegram.Bot.unpin_all_forum_topic_messages`
- Used to unpin all messages in a forum topic
@@ -0,0 +1,3 @@
.. raw:: html
<center><video height="300px" loop autoplay muted><source src="https://core.telegram.org/file/464001555/10fbd/jvTuV2Ke7WQ.1916669.mp4/a056de323645db409d" type="video/mp4"></video></center>
+2 -3
View File
@@ -32,7 +32,6 @@
GitHub Repository <https://github.com/python-telegram-bot/python-telegram-bot/>
Telegram Channel <https://t.me/pythontelegrambotchannel/>
Telegram User Group <https://t.me/pythontelegrambotgroup/>
contributing
coc
contributing
testing
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.Animation
==================
Animation
=========
.. Also lists methods of _BaseThumbedMedium, but not the ones of TelegramObject
+11
View File
@@ -15,6 +15,8 @@ Available Types
telegram.botcommandscopechatadministrators
telegram.botcommandscopechatmember
telegram.botcommandscopedefault
telegram.botdescription
telegram.botshortdescription
telegram.callbackquery
telegram.chat
telegram.chatadministratorrights
@@ -31,6 +33,7 @@ Available Types
telegram.chatmemberupdated
telegram.chatpermissions
telegram.chatphoto
telegram.chatshared
telegram.contact
telegram.dice
telegram.document
@@ -39,7 +42,10 @@ Available Types
telegram.forumtopic
telegram.forumtopicclosed
telegram.forumtopiccreated
telegram.forumtopicedited
telegram.forumtopicreopened
telegram.generalforumtopichidden
telegram.generalforumtopicunhidden
telegram.inlinekeyboardbutton
telegram.inlinekeyboardmarkup
telegram.inputfile
@@ -49,8 +55,11 @@ Available Types
telegram.inputmediadocument
telegram.inputmediaphoto
telegram.inputmediavideo
telegram.inputsticker
telegram.keyboardbutton
telegram.keyboardbuttonpolltype
telegram.keyboardbuttonrequestchat
telegram.keyboardbuttonrequestuser
telegram.location
telegram.loginurl
telegram.menubutton
@@ -73,6 +82,7 @@ Available Types
telegram.update
telegram.user
telegram.userprofilephotos
telegram.usershared
telegram.venue
telegram.video
telegram.videochatended
@@ -84,4 +94,5 @@ Available Types
telegram.webappdata
telegram.webappinfo
telegram.webhookinfo
telegram.writeaccessallowed
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.Audio
==============
Audio
=====
.. Also lists methods of _BaseThumbedMedium, but not the ones of TelegramObject
+4 -3
View File
@@ -1,6 +1,7 @@
telegram.Bot
============
Bot
===
.. autoclass:: telegram.Bot
:members:
:show-inheritance:
:show-inheritance:
:special-members: __reduce__, __deepcopy__
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.BotCommand
===================
BotCommand
==========
.. autoclass:: telegram.BotCommand
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.BotCommandScope
========================
BotCommandScope
===============
.. autoclass:: telegram.BotCommandScope
:members:
@@ -1,5 +1,5 @@
telegram.BotCommandScopeAllChatAdministrators
=============================================
BotCommandScopeAllChatAdministrators
====================================
.. autoclass:: telegram.BotCommandScopeAllChatAdministrators
:members:
@@ -1,5 +1,5 @@
telegram.BotCommandScopeAllGroupChats
=======================================
BotCommandScopeAllGroupChats
============================
.. autoclass:: telegram.BotCommandScopeAllGroupChats
:members:
@@ -1,5 +1,5 @@
telegram.BotCommandScopeAllPrivateChats
=======================================
BotCommandScopeAllPrivateChats
==============================
.. autoclass:: telegram.BotCommandScopeAllPrivateChats
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.BotCommandScopeChat
============================
BotCommandScopeChat
===================
.. autoclass:: telegram.BotCommandScopeChat
:members:
@@ -1,5 +1,5 @@
telegram.BotCommandScopeChatAdministrators
==========================================
BotCommandScopeChatAdministrators
=================================
.. autoclass:: telegram.BotCommandScopeChatAdministrators
:members:
@@ -1,5 +1,5 @@
telegram.BotCommandScopeChatMember
==================================
BotCommandScopeChatMember
=========================
.. autoclass:: telegram.BotCommandScopeChatMember
:members:
@@ -1,5 +1,5 @@
telegram.BotCommandScopeDefault
===============================
BotCommandScopeDefault
======================
.. autoclass:: telegram.BotCommandScopeDefault
:members:
+6
View File
@@ -0,0 +1,6 @@
BotDescription
==============
.. autoclass:: telegram.BotDescription
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
BotShortDescription
===================
.. autoclass:: telegram.BotShortDescription
:members:
:show-inheritance:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.Callbackgame
=====================
Callbackgame
============
.. autoclass:: telegram.CallbackGame
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.CallbackQuery
======================
CallbackQuery
=============
.. autoclass:: telegram.CallbackQuery
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.Chat
=============
Chat
====
.. autoclass:: telegram.Chat
:members:
@@ -1,5 +1,5 @@
telegram.ChatAdministratorRights
================================
ChatAdministratorRights
=======================
.. versionadded:: 20.0
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ChatInviteLink
=======================
ChatInviteLink
==============
.. autoclass:: telegram.ChatInviteLink
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ChatJoinRequest
========================
ChatJoinRequest
===============
.. autoclass:: telegram.ChatJoinRequest
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ChatLocation
=====================
ChatLocation
============
.. autoclass:: telegram.ChatLocation
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ChatMember
===================
ChatMember
==========
.. autoclass:: telegram.ChatMember
:members:
@@ -1,5 +1,5 @@
telegram.ChatMemberAdministrator
================================
ChatMemberAdministrator
=======================
.. autoclass:: telegram.ChatMemberAdministrator
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ChatMemberBanned
=========================
ChatMemberBanned
================
.. autoclass:: telegram.ChatMemberBanned
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ChatMemberLeft
=======================
ChatMemberLeft
==============
.. autoclass:: telegram.ChatMemberLeft
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ChatMemberMember
=========================
ChatMemberMember
================
.. autoclass:: telegram.ChatMemberMember
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ChatMemberOwner
========================
ChatMemberOwner
===============
.. autoclass:: telegram.ChatMemberOwner
:members:
@@ -1,5 +1,5 @@
telegram.ChatMemberRestricted
=============================
ChatMemberRestricted
====================
.. autoclass:: telegram.ChatMemberRestricted
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ChatMemberUpdated
==========================
ChatMemberUpdated
=================
.. autoclass:: telegram.ChatMemberUpdated
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ChatPermissions
========================
ChatPermissions
===============
.. autoclass:: telegram.ChatPermissions
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ChatPhoto
==================
ChatPhoto
=========
.. autoclass:: telegram.ChatPhoto
:members:
+6
View File
@@ -0,0 +1,6 @@
ChatShared
===================
.. autoclass:: telegram.ChatShared
:members:
:show-inheritance:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ChosenInlineResult
===========================
ChosenInlineResult
==================
.. autoclass:: telegram.ChosenInlineResult
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.Contact
================
Contact
=======
.. autoclass:: telegram.Contact
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.Credentials
====================
Credentials
===========
.. autoclass:: telegram.Credentials
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.DataCredentials
========================
DataCredentials
===============
.. autoclass:: telegram.DataCredentials
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.Dice
=============
Dice
====
.. autoclass:: telegram.Dice
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.Document
=================
Document
========
.. Also lists methods of _BaseThumbedMedium, but not the ones of TelegramObject
.. autoclass:: telegram.Document
@@ -1,5 +1,5 @@
telegram.EncryptedCredentials
=============================
EncryptedCredentials
====================
.. autoclass:: telegram.EncryptedCredentials
:members:
@@ -1,5 +1,5 @@
telegram.EncryptedPassportElement
=================================
EncryptedPassportElement
========================
.. autoclass:: telegram.EncryptedPassportElement
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.AIORateLimiter
============================
AIORateLimiter
==============
.. autoclass:: telegram.ext.AIORateLimiter
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.Application
========================
Application
===========
.. autoclass:: telegram.ext.Application
:members:
@@ -1,5 +1,5 @@
telegram.ext.ApplicationBuilder
===============================
ApplicationBuilder
==================
.. autoclass:: telegram.ext.ApplicationBuilder
:members:
@@ -1,5 +1,5 @@
telegram.ext.ApplicationHandlerStop
===================================
ApplicationHandlerStop
======================
.. autoclass:: telegram.ext.ApplicationHandlerStop
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.BaseHandler
========================
BaseHandler
===========
.. autoclass:: telegram.ext.BaseHandler
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.BasePersistence
============================
BasePersistence
===============
.. autoclass:: telegram.ext.BasePersistence
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.BaseRateLimiter
============================
BaseRateLimiter
===============
.. autoclass:: telegram.ext.BaseRateLimiter
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.CallbackContext
============================
CallbackContext
===============
.. autoclass:: telegram.ext.CallbackContext
:members:
@@ -1,5 +1,5 @@
telegram.ext.CallbackDataCache
==============================
CallbackDataCache
=================
.. autoclass:: telegram.ext.CallbackDataCache
:members:
@@ -1,5 +1,5 @@
telegram.ext.CallbackQueryHandler
=================================
CallbackQueryHandler
====================
.. autoclass:: telegram.ext.CallbackQueryHandler
:members:
@@ -1,5 +1,5 @@
telegram.ext.ChatJoinRequestHandler
===================================
ChatJoinRequestHandler
======================
.. autoclass:: telegram.ext.ChatJoinRequestHandler
:members:
@@ -1,5 +1,5 @@
telegram.ext.ChatMemberHandler
==============================
ChatMemberHandler
=================
.. autoclass:: telegram.ext.ChatMemberHandler
:members:
@@ -1,5 +1,5 @@
telegram.ext.ChosenInlineResultHandler
======================================
ChosenInlineResultHandler
=========================
.. autoclass:: telegram.ext.ChosenInlineResultHandler
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.CommandHandler
===========================
CommandHandler
==============
.. autoclass:: telegram.ext.CommandHandler
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.ContextTypes
=========================
ContextTypes
============
.. autoclass:: telegram.ext.ContextTypes
:members:
@@ -1,5 +1,5 @@
telegram.ext.ConversationHandler
================================
ConversationHandler
===================
.. autoclass:: telegram.ext.ConversationHandler
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.Defaults
=====================
Defaults
========
.. autoclass:: telegram.ext.Defaults
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.DictPersistence
============================
DictPersistence
===============
.. autoclass:: telegram.ext.DictPersistence
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.ExtBot
===================
ExtBot
======
.. autoclass:: telegram.ext.ExtBot
:show-inheritance:
+4 -4
View File
@@ -1,11 +1,11 @@
telegram.ext.filters Module
===========================
filters Module
==============
.. :bysource: since e.g filters.CHAT is much above filters.Chat() in the docs when it shouldn't.
The classes in `filters.py` are sorted alphabetically such that :bysource: still is readable
.. automodule:: telegram.ext.filters
:inherited-members:
:inherited-members: BaseFilter, MessageFilter, UpdateFilter
:members:
:show-inheritance:
:member-order: bysource
:member-order: bysource
@@ -1,5 +1,5 @@
telegram.ext.InlineQueryHandler
===============================
InlineQueryHandler
==================
.. autoclass:: telegram.ext.InlineQueryHandler
:members:
@@ -1,5 +1,5 @@
telegram.ext.InvalidCallbackData
================================
InvalidCallbackData
===================
.. autoclass:: telegram.ext.InvalidCallbackData
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.Job
=====================
Job
===
.. autoclass:: telegram.ext.Job
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.JobQueue
=====================
JobQueue
========
.. autoclass:: telegram.ext.JobQueue
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.MessageHandler
===========================
MessageHandler
==============
.. autoclass:: telegram.ext.MessageHandler
:members:
@@ -1,5 +1,5 @@
telegram.ext.PersistenceInput
=============================
PersistenceInput
================
.. autoclass:: telegram.ext.PersistenceInput
:show-inheritance:
@@ -1,5 +1,5 @@
telegram.ext.PicklePersistence
==============================
PicklePersistence
=================
.. autoclass:: telegram.ext.PicklePersistence
:members:
@@ -1,5 +1,5 @@
telegram.ext.PollAnswerHandler
==============================
PollAnswerHandler
=================
.. autoclass:: telegram.ext.PollAnswerHandler
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.PollHandler
========================
PollHandler
===========
.. autoclass:: telegram.ext.PollHandler
:members:
@@ -1,5 +1,5 @@
telegram.ext.PreCheckoutQueryHandler
====================================
PreCheckoutQueryHandler
=======================
.. autoclass:: telegram.ext.PreCheckoutQueryHandler
:members:
+2 -2
View File
@@ -1,5 +1,5 @@
telegram.ext.PrefixHandler
===========================
PrefixHandler
=============
.. autoclass:: telegram.ext.PrefixHandler
:members:

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