mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-19 15:45:13 +00:00
Compare commits
98 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ac52018c2 | |||
| ca7a30963d | |||
| c42a230b96 | |||
| ce9742a602 | |||
| 43279543a3 | |||
| eda2172617 | |||
| 89dfa37dbf | |||
| 3709c2fa93 | |||
| da93fe94ae | |||
| cec34e4bca | |||
| ffe23be992 | |||
| ef1685c436 | |||
| 151123745e | |||
| 0eb11ff3e9 | |||
| dab75fb963 | |||
| 62f89758d7 | |||
| 7a8f4412b2 | |||
| 032a859149 | |||
| 507d6bc0e3 | |||
| bd6a60bb30 | |||
| 3c8f6ed42b | |||
| 6540f288f5 | |||
| 5ab82a9c2b | |||
| 847b97f86e | |||
| efacc3dd1b | |||
| 2ce687c8f1 | |||
| a39a59ee9b | |||
| 06854633ab | |||
| 9a8b208ef7 | |||
| 2f06902518 | |||
| 2bc65560eb | |||
| 79e589b39e | |||
| bd3cdbcdbd | |||
| 9709c03b35 | |||
| 3409f51107 | |||
| 2eae2830f3 | |||
| 28d19c3b9a | |||
| e314e78d06 | |||
| 67a97ae5a7 | |||
| 9248c539d0 | |||
| 6b5e46cc08 | |||
| b3155b2e55 | |||
| ec909e62cf | |||
| 1223e851c3 | |||
| 0b352b043e | |||
| b9d2efdec5 | |||
| 8c692d1008 | |||
| 970d2ab085 | |||
| 60b439ff42 | |||
| b17b0d248d | |||
| e0f36867cc | |||
| 01f689373c | |||
| 1e05381133 | |||
| a05362c79a | |||
| fbf07bf126 | |||
| 3017bf00a4 | |||
| 374875c786 | |||
| 8f9db63f4f | |||
| 1787586902 | |||
| 9c50a38512 | |||
| 3a49372591 | |||
| e637d1733c | |||
| b89f5d6126 | |||
| 6578c76068 | |||
| a967dbe37a | |||
| af76a8485f | |||
| 8a205b10c0 | |||
| 6d70c56159 | |||
| 0913b859d7 | |||
| c3f17bb18e | |||
| 006a290b7b | |||
| 422993b8ab | |||
| 2ac4e009d0 | |||
| efe1392e73 | |||
| 0a673e8f7e | |||
| 86c8cae40d | |||
| f737702544 | |||
| 06f1da576e | |||
| 7a470d57c8 | |||
| 1714bfd8f6 | |||
| 71e4015e22 | |||
| 52237cf00c | |||
| dba7866aab | |||
| 98bed6f01a | |||
| 42d7c8c477 | |||
| 8018e5ff3f | |||
| c39839b026 | |||
| 4213c12c5b | |||
| 97226b1ae3 | |||
| 146ec54a00 | |||
| df8aae0a38 | |||
| 4ccc80f9c1 | |||
| cfc75bb08b | |||
| 51ef571a07 | |||
| 9ce0f49882 | |||
| 5b1e7399a4 | |||
| a83046e1ec | |||
| 44e8292838 |
@@ -26,7 +26,7 @@ Setting things up
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install -r requirements-all.txt
|
||||
$ pip install -r requirements-dev-all.txt
|
||||
|
||||
|
||||
5. Install pre-commit hooks:
|
||||
@@ -194,7 +194,7 @@ Feel free to copy (parts of) the checklist to the PR description to remind you o
|
||||
- Added or updated documentation for the changed class(es) and/or method(s)
|
||||
- Added the new method(s) to ``_extbot.py``
|
||||
- Added or updated ``bot_methods.rst``
|
||||
- Updated the Bot API version number in all places: ``README.rst`` and ``README_RAW.rst`` (including the badge), as well as ``telegram.constants.BOT_API_VERSION_INFO``
|
||||
- Updated the Bot API version number in all places: ``README.rst`` (including the badge) and ``telegram.constants.BOT_API_VERSION_INFO``
|
||||
- Added logic for arbitrary callback data in :class:`telegram.ext.ExtBot` for new methods that either accept a ``reply_markup`` in some form or have a return type that is/contains :class:`~telegram.Message`
|
||||
|
||||
Documenting
|
||||
@@ -210,13 +210,8 @@ 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're running Python 3.9 or above and have the required dependencies:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install -r docs/requirements-docs.txt
|
||||
|
||||
then run the following from the PTB root directory:
|
||||
We use `sphinx`_ to generate static HTML docs. To build them, first make sure you're running Python 3.10 or above and have the required dependencies installed as explained above.
|
||||
Then, run the following from the PTB root directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: Bug Report
|
||||
description: Create a report to help us improve
|
||||
title: "[BUG]"
|
||||
labels: ["bug :bug:"]
|
||||
labels: ["📋 triage"]
|
||||
type: '🐛 bug'
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: Feature Request
|
||||
description: Suggest an idea for this project
|
||||
title: "[FEATURE]"
|
||||
labels: ["enhancement"]
|
||||
labels: ["📋 triage"]
|
||||
type: '💡 feature'
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: Question
|
||||
description: Get help with errors or general questions
|
||||
title: "[QUESTION]"
|
||||
labels: ["question"]
|
||||
type: '❔ question'
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
version: 1
|
||||
|
||||
labels:
|
||||
- label: "dependencies"
|
||||
- label: "⚙️ dependencies"
|
||||
authors: ["dependabot[bot]", "pre-commit-ci[bot]"]
|
||||
- label: "code quality ✨"
|
||||
- label: "🛠 code-quality"
|
||||
authors: ["pre-commit-ci[bot]"]
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
- name: Fetch Dependabot metadata
|
||||
id: dependabot-metadata
|
||||
uses: dependabot/fetch-metadata@v2.1.0
|
||||
uses: dependabot/fetch-metadata@v2.2.0
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
@@ -3,6 +3,9 @@ on:
|
||||
schedule:
|
||||
# First day of month at 05:46 in every 2nd month
|
||||
- cron: '46 5 1 */2 *'
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/docs-linkcheck.yml
|
||||
|
||||
jobs:
|
||||
test-sphinx-build:
|
||||
@@ -10,7 +13,7 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.9]
|
||||
python-version: ['3.10']
|
||||
os: [ubuntu-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
@@ -22,6 +25,6 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -W ignore -m pip install --upgrade pip
|
||||
python -W ignore -m pip install -r requirements-all.txt
|
||||
python -W ignore -m pip install -r requirements-dev-all.txt
|
||||
- name: Check Links
|
||||
run: sphinx-build docs/source docs/build/html -W --keep-going -j auto -b linkcheck
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.9]
|
||||
python-version: ['3.10']
|
||||
os: [ubuntu-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -W ignore -m pip install --upgrade pip
|
||||
python -W ignore -m pip install -r requirements-all.txt
|
||||
python -W ignore -m pip install -r requirements-dev-all.txt
|
||||
- name: Test autogeneration of admonitions
|
||||
run: pytest -v --tb=short tests/docs/admonition_inserter.py
|
||||
- name: Build docs
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
pull-requests: write # for srvaroa/labeler to add labels in PR
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: srvaroa/labeler@v1.10.1
|
||||
- uses: srvaroa/labeler@v1.12.0
|
||||
# Config file at .github/labeler.yml
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
name: Warning maintainers
|
||||
on:
|
||||
pull_request_target:
|
||||
paths:
|
||||
- requirements.txt
|
||||
- requirements-opts.txt
|
||||
- .pre-commit-config.yaml
|
||||
permissions:
|
||||
pull-requests: write
|
||||
jobs:
|
||||
job:
|
||||
runs-on: ubuntu-latest
|
||||
name: about pre-commit and dependency change
|
||||
steps:
|
||||
- name: running the check
|
||||
uses: Poolitzer/notifier-action@master
|
||||
with:
|
||||
notify-message: Hey! Looks like you edited the (optional) requirements or the pre-commit hooks. I'm just a friendly reminder to keep the additional dependencies for the hooks in sync with the requirements :)
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -1,18 +0,0 @@
|
||||
name: Warning maintainers
|
||||
on:
|
||||
pull_request_target:
|
||||
paths:
|
||||
- README.rst
|
||||
- README_RAW.rst
|
||||
permissions:
|
||||
pull-requests: write
|
||||
jobs:
|
||||
job:
|
||||
runs-on: ubuntu-latest
|
||||
name: about readme change
|
||||
steps:
|
||||
- name: running the check
|
||||
uses: Poolitzer/notifier-action@master
|
||||
with:
|
||||
notify-message: Hey! Looks like you edited README.rst or README_RAW.rst. I'm just a friendly reminder to apply relevant changes to both of those files :)
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,129 @@
|
||||
name: Publish to PyPI
|
||||
|
||||
on:
|
||||
# manually trigger the workflow
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Distribution
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
TAG: ${{ steps.get_tag.outputs.TAG }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Install pypa/build
|
||||
run: >-
|
||||
python3 -m pip install build --user
|
||||
- name: Build a binary wheel and a source tarball
|
||||
run: python3 -m build
|
||||
- name: Store the distribution packages
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
- name: Get Tag Name
|
||||
id: get_tag
|
||||
run: |
|
||||
pip install .
|
||||
TAG=$(python -c "from telegram import __version__; print(f'v{__version__}')")
|
||||
echo "TAG=$TAG" >> $GITHUB_OUTPUT
|
||||
|
||||
publish-to-pypi:
|
||||
name: Publish to PyPI
|
||||
needs:
|
||||
- build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: release_pypi
|
||||
url: https://pypi.org/p/python-telegram-bot
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: mandatory for trusted publishing
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
- name: Publish to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
|
||||
compute-signatures:
|
||||
name: Compute SHA1 Sums and Sign with Sigstore
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- publish-to-pypi
|
||||
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: mandatory for sigstore
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
- name: Compute SHA1 Sums
|
||||
run: |
|
||||
# Compute SHA1 sum of the distribution packages and save it to a file with the same name,
|
||||
# but with .sha1 extension
|
||||
for file in dist/*; do
|
||||
sha1sum $file > $file.sha1
|
||||
done
|
||||
- name: Sign the dists with Sigstore
|
||||
uses: sigstore/gh-action-sigstore-python@v3.0.0
|
||||
with:
|
||||
inputs: >-
|
||||
./dist/*.tar.gz
|
||||
./dist/*.whl
|
||||
- name: Store the distribution packages and signatures
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: python-package-distributions-and-signatures
|
||||
path: dist/
|
||||
|
||||
github-release:
|
||||
name: Upload to GitHub Release
|
||||
needs:
|
||||
- build
|
||||
- compute-signatures
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: write # IMPORTANT: mandatory for making GitHub Releases
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: python-package-distributions-and-signatures
|
||||
path: dist/
|
||||
- name: Create GitHub Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ needs.build.outputs.TAG }}
|
||||
# Create a tag and a GitHub Release. The description can be changed later, as for now
|
||||
# we don't define it through this workflow.
|
||||
run: >-
|
||||
gh release create
|
||||
'${{ env.TAG }}'
|
||||
--repo '${{ github.repository }}'
|
||||
--generate-notes
|
||||
- name: Upload artifact signatures to GitHub Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ needs.build.outputs.TAG }}
|
||||
# Upload to GitHub Release using the `gh` CLI.
|
||||
# `dist/` contains the built packages, and the
|
||||
# sigstore-produced signatures and certificates.
|
||||
run: >-
|
||||
gh release upload
|
||||
'${{ env.TAG }}' dist/**
|
||||
--repo '${{ github.repository }}'
|
||||
@@ -0,0 +1,132 @@
|
||||
name: Publish to Test PyPI
|
||||
|
||||
on:
|
||||
# manually trigger the workflow
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Distribution
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
TAG: ${{ steps.get_tag.outputs.TAG }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Install pypa/build
|
||||
run: >-
|
||||
python3 -m pip install build --user
|
||||
- name: Build a binary wheel and a source tarball
|
||||
run: python3 -m build
|
||||
- name: Store the distribution packages
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
- name: Get Tag Name
|
||||
id: get_tag
|
||||
run: |
|
||||
pip install .
|
||||
TAG=$(python -c "from telegram import __version__; print(f'v{__version__}')")
|
||||
echo "TAG=$TAG" >> $GITHUB_OUTPUT
|
||||
|
||||
publish-to-test-pypi:
|
||||
name: Publish to Test PyPI
|
||||
needs:
|
||||
- build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: release_test_pypi
|
||||
url: https://test.pypi.org/p/python-telegram-bot
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: mandatory for trusted publishing
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
- name: Publish to Test PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
|
||||
compute-signatures:
|
||||
name: Compute SHA1 Sums and Sign with Sigstore
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- publish-to-test-pypi
|
||||
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: mandatory for sigstore
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
- name: Compute SHA1 Sums
|
||||
run: |
|
||||
# Compute SHA1 sum of the distribution packages and save it to a file with the same name,
|
||||
# but with .sha1 extension
|
||||
for file in dist/*; do
|
||||
sha1sum $file > $file.sha1
|
||||
done
|
||||
- name: Sign the dists with Sigstore
|
||||
uses: sigstore/gh-action-sigstore-python@v3.0.0
|
||||
with:
|
||||
inputs: >-
|
||||
./dist/*.tar.gz
|
||||
./dist/*.whl
|
||||
- name: Store the distribution packages and signatures
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: python-package-distributions-and-signatures
|
||||
path: dist/
|
||||
|
||||
github-test-release:
|
||||
name: Upload to GitHub Release Draft
|
||||
needs:
|
||||
- build
|
||||
- compute-signatures
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: write # IMPORTANT: mandatory for making GitHub Releases
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: python-package-distributions-and-signatures
|
||||
path: dist/
|
||||
- name: Create GitHub Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ needs.build.outputs.TAG }}
|
||||
# Create a GitHub Release *draft*. The description can be changed later, as for now
|
||||
# we don't define it through this workflow.
|
||||
run: >-
|
||||
gh release create
|
||||
'${{ env.TAG }}'
|
||||
--repo '${{ github.repository }}'
|
||||
--generate-notes
|
||||
--draft
|
||||
- name: Upload artifact signatures to GitHub Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ needs.build.outputs.TAG }}
|
||||
# Upload to GitHub Release using the `gh` CLI.
|
||||
# `dist/` contains the built packages, and the
|
||||
# sigstore-produced signatures and certificates.
|
||||
run: >-
|
||||
gh release upload
|
||||
'${{ env.TAG }}' dist/**
|
||||
--repo '${{ github.repository }}'
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
days-before-stale: 3
|
||||
days-before-close: 2
|
||||
days-before-pr-stale: -1
|
||||
stale-issue-label: 'stale'
|
||||
stale-issue-label: '📋 stale'
|
||||
only-labels: 'question'
|
||||
stale-issue-message: ''
|
||||
close-issue-message: 'This issue has been automatically closed due to inactivity. Feel free to comment in order to reopen or ask again in our Telegram support group at https://t.me/pythontelegrambotgroup.'
|
||||
|
||||
@@ -29,9 +29,8 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -W ignore -m pip install --upgrade pip
|
||||
python -W ignore -m pip install -r requirements.txt
|
||||
python -W ignore -m pip install -r requirements-opts.txt
|
||||
python -W ignore -m pip install -r requirements-dev.txt
|
||||
python -W ignore -m pip install .[all]
|
||||
python -W ignore -m pip install -r requirements-unit-tests.txt
|
||||
- name: Compare to official api
|
||||
run: |
|
||||
pytest -v tests/test_official/test_official.py --junit-xml=.test_report_official.xml
|
||||
@@ -42,7 +41,7 @@ jobs:
|
||||
|
||||
- name: Test Summary
|
||||
id: test_summary
|
||||
uses: test-summary/action@v2.3
|
||||
uses: test-summary/action@v2.4
|
||||
if: always() # always run, even if tests fail
|
||||
with:
|
||||
paths: .test_report_official.xml
|
||||
|
||||
@@ -3,8 +3,8 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- telegram/**
|
||||
- requirements.txt
|
||||
- requirements-opts.txt
|
||||
- pyproject.toml
|
||||
- .github/workflows/type_completeness.yml
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
@@ -14,66 +14,8 @@ jobs:
|
||||
name: test-type-completeness
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- 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@v5
|
||||
- uses: Bibo-Joshi/pyright-type-completeness@1.0.1
|
||||
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.316
|
||||
- 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"This PR changes type completeness from {round(base, 3)} to {round(pr, 3)}."
|
||||
|
||||
if base == 0:
|
||||
text = f"Something is broken in the workflow. Reported type completeness is 0. 💥"
|
||||
set_summary(text)
|
||||
print(Path("pr.readable").read_text(encoding="utf-8"))
|
||||
error(text)
|
||||
exit(1)
|
||||
|
||||
if pr < (base - 0.001):
|
||||
text = f"{base_text} ❌"
|
||||
set_summary(text)
|
||||
print(Path("pr.readable").read_text(encoding="utf-8"))
|
||||
error(text)
|
||||
exit(1)
|
||||
elif pr > (base + 0.001):
|
||||
text = f"{base_text} ✨"
|
||||
set_summary(text)
|
||||
if pr < 1:
|
||||
print(Path("pr.readable").read_text(encoding="utf-8"))
|
||||
print(text)
|
||||
else:
|
||||
text = f"{base_text} This is less than 0.1 percentage points. ✅"
|
||||
set_summary(text)
|
||||
print(Path("pr.readable").read_text(encoding="utf-8"))
|
||||
print(text)
|
||||
package-name: telegram
|
||||
python-version: 3.12
|
||||
pyright-version: ~=1.1.367
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
name: Check Type Completeness Monthly Run
|
||||
on:
|
||||
schedule:
|
||||
# Run first friday of the month at 03:17 - odd time to spread load on GitHub Actions
|
||||
- cron: '17 3 1-7 * 5'
|
||||
|
||||
jobs:
|
||||
test-type-completeness:
|
||||
name: test-type-completeness
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Bibo-Joshi/pyright-type-completeness@1.0.1
|
||||
id: pyright-type-completeness
|
||||
with:
|
||||
package-name: telegram
|
||||
python-version: 3.12
|
||||
pyright-version: ~=1.1.367
|
||||
- name: Check Output
|
||||
uses: jannekem/run-python-script-action@v1
|
||||
env:
|
||||
TYPE_COMPLETENESS: ${{ steps.pyright-type-completeness.outputs.base-completeness-score }}
|
||||
with:
|
||||
script: |
|
||||
import os
|
||||
completeness = float(os.getenv("TYPE_COMPLETENESS"))
|
||||
|
||||
if completeness >= 1:
|
||||
exit(0)
|
||||
|
||||
text = f"Type Completeness Decreased to {completeness}. ❌"
|
||||
error(text)
|
||||
set_summary(text)
|
||||
exit(1)
|
||||
@@ -4,9 +4,9 @@ on:
|
||||
paths:
|
||||
- telegram/**
|
||||
- tests/**
|
||||
- requirements.txt
|
||||
- requirements-opts.txt
|
||||
- requirements-dev.txt
|
||||
- .github/workflows/unit_tests.yml
|
||||
- pyproject.toml
|
||||
- requirements-unit-tests.txt
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
|
||||
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
@@ -35,9 +35,9 @@ jobs:
|
||||
run: |
|
||||
python -W ignore -m pip install --upgrade pip
|
||||
python -W ignore -m pip install -U pytest-cov
|
||||
python -W ignore -m pip install -r requirements.txt
|
||||
python -W ignore -m pip install -r requirements-dev.txt
|
||||
python -W ignore -m pip install pytest-xdist[psutil]
|
||||
python -W ignore -m pip install .
|
||||
python -W ignore -m pip install -r requirements-unit-tests.txt
|
||||
python -W ignore -m pip install pytest-xdist
|
||||
|
||||
- name: Test with pytest
|
||||
# We run 4 different suites here
|
||||
@@ -57,21 +57,17 @@ jobs:
|
||||
# - without socks support
|
||||
# - without http2 support
|
||||
TO_TEST="test_no_passport.py or test_datetime.py or test_defaults.py or test_jobqueue.py or test_applicationbuilder.py or test_ratelimiter.py or test_updater.py or test_callbackdatacache.py or test_request.py"
|
||||
pytest -v --cov -k "${TO_TEST}"
|
||||
# Rerun only failed tests (--lf), and don't run any tests if none failed (--lfnf=none)
|
||||
pytest -v --cov --cov-append -k "${TO_TEST}" --lf --lfnf=none --junit-xml=.test_report_no_optionals.xml
|
||||
# No tests were selected, convert returned status code to 0
|
||||
opt_dep_status=$(( $? == 5 ? 0 : $? ))
|
||||
pytest -v --cov -k "${TO_TEST}" --junit-xml=.test_report_no_optionals_junit.xml
|
||||
opt_dep_status=$?
|
||||
|
||||
# Test the rest
|
||||
export TEST_WITH_OPT_DEPS='true'
|
||||
pip install -r requirements-opts.txt
|
||||
# `-n auto --dist loadfile` uses pytest-xdist to run each test file on a different CPU
|
||||
# worker. Increasing number of workers has little effect on test duration, but it seems
|
||||
# to increase flakyness, specially on python 3.7 with --dist=loadgroup.
|
||||
pytest -v --cov --cov-append -n auto --dist loadfile
|
||||
pytest -v --cov --cov-append -n auto --dist loadfile --lf --lfnf=none --junit-xml=.test_report_optionals.xml
|
||||
main_status=$(( $? == 5 ? 0 : $? ))
|
||||
pip install .[all]
|
||||
# `-n auto --dist worksteal` uses pytest-xdist to run tests on multiple CPU
|
||||
# workers. Increasing number of workers has little effect on test duration, but it seems
|
||||
# to increase flakyness.
|
||||
pytest -v --cov --cov-append -n auto --dist worksteal --junit-xml=.test_report_optionals_junit.xml
|
||||
main_status=$?
|
||||
# exit with non-zero status if any of the two pytest runs failed
|
||||
exit $(( ${opt_dep_status} || ${main_status} ))
|
||||
env:
|
||||
@@ -83,17 +79,23 @@ jobs:
|
||||
|
||||
- name: Test Summary
|
||||
id: test_summary
|
||||
uses: test-summary/action@v2.3
|
||||
uses: test-summary/action@v2.4
|
||||
if: always() # always run, even if tests fail
|
||||
with:
|
||||
paths: |
|
||||
.test_report_no_optionals.xml
|
||||
.test_report_optionals.xml
|
||||
.test_report_no_optionals_junit.xml
|
||||
.test_report_optionals_junit.xml
|
||||
|
||||
- name: Submit coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
env_vars: OS,PYTHON
|
||||
name: ${{ matrix.os }}-${{ matrix.python-version }}
|
||||
fail_ci_if_error: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
- name: Upload test results to Codecov
|
||||
uses: codecov/test-results-action@v1
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
files: .test_report_no_optionals_junit.xml,.test_report_optionals_junit.xml
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
@@ -92,3 +92,6 @@ telegram.jpg
|
||||
|
||||
# virtual env
|
||||
venv*
|
||||
|
||||
# environment manager:
|
||||
.mise.toml
|
||||
+14
-14
@@ -1,4 +1,4 @@
|
||||
# Make sure that the additional_dependencies here match requirements(-opts).txt
|
||||
# Make sure that the additional_dependencies here match pyproject.toml
|
||||
|
||||
ci:
|
||||
autofix_prs: false
|
||||
@@ -7,7 +7,7 @@ ci:
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: 'v0.4.3'
|
||||
rev: 'v0.5.6'
|
||||
hooks:
|
||||
- id: ruff
|
||||
name: ruff
|
||||
@@ -15,8 +15,8 @@ repos:
|
||||
- httpx~=0.27
|
||||
- tornado~=6.4
|
||||
- APScheduler~=3.10.4
|
||||
- cachetools~=5.3.3
|
||||
- aiolimiter~=1.1.0
|
||||
- cachetools>=5.3.3,<5.5.0
|
||||
- aiolimiter~=1.1,<1.3
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 24.4.2
|
||||
hooks:
|
||||
@@ -25,11 +25,11 @@ repos:
|
||||
- --diff
|
||||
- --check
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 7.0.0
|
||||
rev: 7.1.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/PyCQA/pylint
|
||||
rev: v3.1.0
|
||||
rev: v3.3.2
|
||||
hooks:
|
||||
- id: pylint
|
||||
files: ^(?!(tests|docs)).*\.py$
|
||||
@@ -37,11 +37,11 @@ repos:
|
||||
- httpx~=0.27
|
||||
- tornado~=6.4
|
||||
- APScheduler~=3.10.4
|
||||
- cachetools~=5.3.3
|
||||
- aiolimiter~=1.1.0
|
||||
- cachetools>=5.3.3,<5.5.0
|
||||
- aiolimiter~=1.1,<1.3
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.10.0
|
||||
rev: v1.10.1
|
||||
hooks:
|
||||
- id: mypy
|
||||
name: mypy-ptb
|
||||
@@ -53,8 +53,8 @@ repos:
|
||||
- httpx~=0.27
|
||||
- tornado~=6.4
|
||||
- APScheduler~=3.10.4
|
||||
- cachetools~=5.3.3
|
||||
- aiolimiter~=1.1.0
|
||||
- cachetools>=5.3.3,<5.5.0
|
||||
- aiolimiter~=1.1,<1.3
|
||||
- . # this basically does `pip install -e .`
|
||||
- id: mypy
|
||||
name: mypy-examples
|
||||
@@ -65,14 +65,14 @@ repos:
|
||||
additional_dependencies:
|
||||
- tornado~=6.4
|
||||
- APScheduler~=3.10.4
|
||||
- cachetools~=5.3.3
|
||||
- cachetools>=5.3.3,<5.5.0
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.15.2
|
||||
rev: v3.16.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args:
|
||||
- --py38-plus
|
||||
- --py39-plus
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.13.2
|
||||
hooks:
|
||||
|
||||
@@ -23,6 +23,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
|
||||
- `Abdelrahman <https://github.com/aelkheir>`_
|
||||
- `Abshar <https://github.com/abxhr>`_
|
||||
- `Abubakar Alaya <https://github.com/Ecode2>`_
|
||||
- `Alateas <https://github.com/alateas>`_
|
||||
- `Ales Dokshanin <https://github.com/alesdokshanin>`_
|
||||
- `Alexandre <https://github.com/xTudoS>`_
|
||||
@@ -60,6 +61,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `Hugo Damer <https://github.com/HakimusGIT>`_
|
||||
- `ihoru <https://github.com/ihoru>`_
|
||||
- `Iulian Onofrei <https://github.com/revolter>`_
|
||||
- `Jainam Oswal <https://github.com/jainamoswal>`_
|
||||
- `Jasmin Bom <https://github.com/jsmnbom>`_
|
||||
- `JASON0916 <https://github.com/JASON0916>`_
|
||||
- `jeffffc <https://github.com/jeffffc>`_
|
||||
@@ -79,6 +81,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `LRezende <https://github.com/lrezende>`_
|
||||
- `Luca Bellanti <https://github.com/Trifase>`_
|
||||
- `Lucas Molinari <https://github.com/lucasmolinari>`_
|
||||
- `Luis Pérez <https://github.com/nemacysts>`_
|
||||
- `macrojames <https://github.com/macrojames>`_
|
||||
- `Matheus Lemos <https://github.com/mlemosf>`_
|
||||
- `Michael Dix <https://github.com/Eisberge>`_
|
||||
@@ -86,6 +89,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `Miguel C. R. <https://github.com/MiguelX413>`_
|
||||
- `miles <https://github.com/miles170>`_
|
||||
- `Mischa Krüger <https://github.com/Makman2>`_
|
||||
- `Mohd Yusuf <https://github.com/mohdyusuf2312>`_
|
||||
- `naveenvhegde <https://github.com/naveenvhegde>`_
|
||||
- `neurrone <https://github.com/neurrone>`_
|
||||
- `NikitaPirate <https://github.com/NikitaPirate>`_
|
||||
@@ -96,6 +100,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `Oleg Sushchenko <https://github.com/feuillemorte>`_
|
||||
- `Or Bin <https://github.com/OrBin>`_
|
||||
- `overquota <https://github.com/overquota>`_
|
||||
- `Pablo Martinez <https://github.com/elpekenin>`_
|
||||
- `Paradox <https://github.com/paradox70>`_
|
||||
- `Patrick Hofmann <https://github.com/PH89>`_
|
||||
- `Paul Larsen <https://github.com/PaulSonOfLars>`_
|
||||
@@ -107,11 +112,13 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `Rahiel Kasim <https://github.com/rahiel>`_
|
||||
- `Riko Naka <https://github.com/rikonaka>`_
|
||||
- `Rizlas <https://github.com/rizlas>`_
|
||||
- `Snehashish Biswas <https://github.com/Snehashish06>`_
|
||||
- `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>`_
|
||||
- `Siloé Garcez <https://github.com/roast-lord>`_
|
||||
- `Simon Schürrle <https://github.com/SitiSchu>`_
|
||||
- `sooyhwang <https://github.com/sooyhwang>`_
|
||||
- `syntx <https://github.com/syntx>`_
|
||||
|
||||
+228
@@ -4,6 +4,234 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
Version 21.9
|
||||
============
|
||||
|
||||
*Released 2024-12-07*
|
||||
|
||||
This is the technical changelog for version 21.9. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Major Changes
|
||||
-------------
|
||||
|
||||
- Full Support for Bot API 8.1 (:pr:`4594` closes :issue:`4592`)
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- Use ``MessageLimit.DEEP_LINK_LENGTH`` in ``helpers.create_deep_linked_url`` (:pr:`4597` by `nemacysts <https://github.com/nemacysts>`_)
|
||||
- Allow ``Sequence`` Input for ``allowed_updates`` in ``Application`` and ``Updater`` Methods (:pr:`4589` by `nemacysts <https://github.com/nemacysts>`_)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- Update ``aiolimiter`` requirement from ~=1.1.0 to >=1.1,<1.3 (:pr:`4595`)
|
||||
- Bump ``pytest`` from 8.3.3 to 8.3.4 (:pr:`4596`)
|
||||
- Bump ``codecov/codecov-action`` from 4 to 5 (:pr:`4585`)
|
||||
- Bump ``pylint`` to v3.3.2 to Improve Python 3.13 Support (:pr:`4590` by `nemacysts <https://github.com/nemacysts>`_)
|
||||
- Bump ``srvaroa/labeler`` from 1.11.1 to 1.12.0 (:pr:`4586`)
|
||||
|
||||
Version 21.8
|
||||
============
|
||||
*Released 2024-12-01*
|
||||
|
||||
This is the technical changelog for version 21.8. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Major Changes
|
||||
-------------
|
||||
|
||||
- Full Support for Bot API 8.0 (:pr:`4568`, :pr:`4566` closes :issue:`4567`, :pr:`4572`, :pr:`4571`, :pr:`4570`, :pr:`4576`, :pr:`4574`)
|
||||
|
||||
Documentation Improvements
|
||||
--------------------------
|
||||
|
||||
- Documentation Improvements (:pr:`4565` by `Snehashish06 <https://github.com/Snehashish06>`_, :pr:`4573`)
|
||||
|
||||
Version 21.7
|
||||
============
|
||||
*Released 2024-11-04*
|
||||
|
||||
This is the technical changelog for version 21.7. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Major Changes
|
||||
-------------
|
||||
|
||||
- Full Support for Bot API 7.11 (:pr:`4546` closes :issue:`4543`)
|
||||
- Add ``Message.reply_paid_media`` (:pr:`4551`)
|
||||
- Drop Support for Python 3.8 (:pr:`4398` by `elpekenin <https://github.com/elpekenin>`_)
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- Allow ``Sequence`` in ``Application.add_handlers`` (:pr:`4531` by `roast-lord <https://github.com/roast-lord>`_ closes :issue:`4530`)
|
||||
- Improve Exception Handling in ``File.download_*`` (:pr:`4542`)
|
||||
- Use Stable Python 3.13 Release in Test Suite (:pr:`4535`)
|
||||
|
||||
Documentation Improvements
|
||||
--------------------------
|
||||
|
||||
- Documentation Improvements (:pr:`4536` by `Ecode2 <https://github.com/Ecode2>`_, :pr:`4556`)
|
||||
- Fix Linkcheck Workflow (:pr:`4545`)
|
||||
- Use ``sphinx-build-compatibility`` to Keep Sphinx Compatibility (:pr:`4492`)
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Improve Test Instability Caused by ``Message`` Fixtures (:pr:`4507`)
|
||||
- Stabilize Some Flaky Tests (:pr:`4500`)
|
||||
- Reduce Creation of HTTP Clients in Tests (:pr:`4493`)
|
||||
- Update ``pytest-xdist`` Usage (:pr:`4491`)
|
||||
- Fix Failing Tests by Making Them Independent (:pr:`4494`)
|
||||
- Introduce Codecov's Test Analysis (:pr:`4487`)
|
||||
- Maintenance Work on ``Bot`` Tests (:pr:`4489`)
|
||||
- Introduce ``conftest.py`` for File Related Tests (:pr:`4488`)
|
||||
- Update Issue Templates to Use Issue Types (:pr:`4553`)
|
||||
- Update Automation to Label Changes (:pr:`4552`)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- Bump ``srvaroa/labeler`` from 1.11.0 to 1.11.1 (:pr:`4549`)
|
||||
- Bump ``sphinx`` from 8.0.2 to 8.1.3 (:pr:`4532`)
|
||||
- Bump ``sphinxcontrib-mermaid`` from 0.9.2 to 1.0.0 (:pr:`4529`)
|
||||
- Bump ``srvaroa/labeler`` from 1.10.1 to 1.11.0 (:pr:`4509`)
|
||||
- Bump ``Bibo-Joshi/pyright-type-completeness`` from 1.0.0 to 1.0.1 (:pr:`4510`)
|
||||
|
||||
Version 21.6
|
||||
============
|
||||
|
||||
*Released 2024-09-19*
|
||||
|
||||
This is the technical changelog for version 21.6. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
- Full Support for Bot API 7.10 (:pr:`4461` closes :issue:`4459`, :pr:`4460`, :pr:`4463` by `aelkheir <https://github.com/aelkheir>`_, :pr:`4464`)
|
||||
- Add Parameter ``httpx_kwargs`` to ``HTTPXRequest`` (:pr:`4451` closes :issue:`4424`)
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- Improve Type Completeness (:pr:`4466`)
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Update Python 3.13 Test Suite to RC2 (:pr:`4471`)
|
||||
- Enforce the ``offline_bot`` Fixture in ``Test*WithoutRequest`` (:pr:`4465`)
|
||||
- Make Tests for ``telegram.ext`` Independent of Networking (:pr:`4454`)
|
||||
- Rename Testing Base Classes (:pr:`4453`)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- Bump ``pytest`` from 8.3.2 to 8.3.3 (:pr:`4475`)
|
||||
|
||||
Version 21.5
|
||||
============
|
||||
|
||||
*Released 2024-09-01*
|
||||
|
||||
This is the technical changelog for version 21.5. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Major Changes
|
||||
-------------
|
||||
|
||||
- Full Support for Bot API 7.9 (:pr:`4429`)
|
||||
- Full Support for Bot API 7.8 (:pr:`4408`)
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
- Add ``MessageEntity.shift_entities`` and ``MessageEntity.concatenate`` (:pr:`4376` closes :issue:`4372`)
|
||||
- Add Parameter ``game_pattern`` to ``CallbackQueryHandler`` (:pr:`4353` by `jainamoswal <https://github.com/jainamoswal>`_ closes :issue:`4269`)
|
||||
- Add Parameter ``read_file_handle`` to ``InputFile`` (:pr:`4388` closes :issue:`4339`)
|
||||
|
||||
Documentation Improvements
|
||||
--------------------------
|
||||
|
||||
- Bugfix for "Available In" Admonitions (:pr:`4413`)
|
||||
- Documentation Improvements (:pr:`4400` closes :issue:`4446`, :pr:`4448` by `Palaptin <https://github.com/Palaptin>`_)
|
||||
- Document Return Types of ``RequestData`` Members (:pr:`4396`)
|
||||
- Add Introductory Paragraphs to Telegram Types Subsections (:pr:`4389` by `mohdyusuf2312 <https://github.com/mohdyusuf2312>`_ closes :issue:`4380`)
|
||||
- Start Adapting to RTD Addons (:pr:`4386`)
|
||||
|
||||
Minor and Internal Changes
|
||||
---------------------------
|
||||
|
||||
- Remove Surplus Logging from ``Updater`` Network Loop (:pr:`4432` by `MartinHjelmare <https://github.com/MartinHjelmare>`_)
|
||||
- Add Internal Constants for Encodings (:pr:`4378` by `elpekenin <https://github.com/elpekenin>`_)
|
||||
- Improve PyPI Automation (:pr:`4375` closes :issue:`4373`)
|
||||
- Update Test Suite to New Test Channel Setup (:pr:`4435`)
|
||||
- Improve Fixture Usage in ``test_message.py`` (:pr:`4431` by `Palaptin <https://github.com/Palaptin>`_)
|
||||
- Update Python 3.13 Test Suite to RC1 (:pr:`4415`)
|
||||
- Bump ``ruff`` and Add New Rules (:pr:`4416`)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- Update ``cachetools`` requirement from <5.5.0,>=5.3.3 to >=5.3.3,<5.6.0 (:pr:`4437`)
|
||||
- Bump ``sphinx`` from 7.4.7 to 8.0.2 and ``furo`` from 2024.7.18 to 2024.8.6 (:pr:`4412`)
|
||||
- Bump ``test-summary/action`` from 2.3 to 2.4 (:pr:`4410`)
|
||||
- Bump ``pytest`` from 8.2.2 to 8.3.2 (:pr:`4403`)
|
||||
- Bump ``dependabot/fetch-metadata`` from 2.1.0 to 2.2.0 (:pr:`4411`)
|
||||
- Update ``cachetools`` requirement from ~=5.3.3 to >=5.3.3,<5.5.0 (:pr:`4390`)
|
||||
- Bump ``sphinx`` from 7.3.7 to 7.4.7 (:pr:`4395`)
|
||||
- Bump ``furo`` from 2024.5.6 to 2024.7.18 (:pr:`4392`)
|
||||
|
||||
Version 21.4
|
||||
============
|
||||
|
||||
*Released 2024-07-12*
|
||||
|
||||
This is the technical changelog for version 21.4. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Major Changes
|
||||
-------------
|
||||
|
||||
- Full Support for Bot API 7.5 (:pr:`4328`, :pr:`4316`, :pr:`4315`, :pr:`4312` closes :issue:`4310`, :pr:`4311`)
|
||||
- Full Support for Bot API 7.6 (:pr:`4333` closes :issue:`4331`, :pr:`4344`, :pr:`4341`, :pr:`4334`, :pr:`4335`, :pr:`4351`, :pr:`4342`, :pr:`4348`)
|
||||
- Full Support for Bot API 7.7 (:pr:`4356` closes :issue:`4355`)
|
||||
- Drop ``python-telegram-bot-raw`` And Switch to ``pyproject.toml`` Based Packaging (:pr:`4288` closes :issue:`4129` and :issue:`4296`)
|
||||
- Deprecate Inclusion of ``successful_payment`` in ``Message.effective_attachment`` (:pr:`4365` closes :issue:`4350`)
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
- Add Support for Python 3.13 Beta (:pr:`4253`)
|
||||
- Add ``filters.PAID_MEDIA`` (:pr:`4357`)
|
||||
- Log Received Data on Deserialization Errors (:pr:`4304`)
|
||||
- Add ``MessageEntity.adjust_message_entities_to_utf_16`` Utility Function (:pr:`4323` by `Antares0982 <https://github.com/Antares0982>`_ closes :issue:`4319`)
|
||||
- Make Argument ``bot`` of ``TelegramObject.de_json`` Optional (:pr:`4320`)
|
||||
|
||||
Documentation Improvements
|
||||
--------------------------
|
||||
|
||||
- Documentation Improvements (:pr:`4303` closes :issue:`4301`)
|
||||
- Restructure Readme (:pr:`4362`)
|
||||
- Fix Link-Check Workflow (:pr:`4332`)
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Automate PyPI Releases (:pr:`4364` closes :issue:`4318`)
|
||||
- Add ``mise-en-place`` to ``.gitignore`` (:pr:`4300`)
|
||||
- Use a Composite Action for Testing Type Completeness (:pr:`4367`)
|
||||
- Stabilize Some Concurrency Usages in Test Suite (:pr:`4360`)
|
||||
- Add a Test Case for ``MenuButton`` (:pr:`4363`)
|
||||
- Extend ``SuccessfulPayment`` Test (:pr:`4349`)
|
||||
- Small Fixes for ``test_stars.py`` (:pr:`4347`)
|
||||
- Use Python 3.13 Beta 3 in Test Suite (:pr:`4336`)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- Bump ``ruff`` and Add New Rules (:pr:`4329`)
|
||||
- Bump ``pre-commit`` Hooks to Latest Versions (:pr:`4337`)
|
||||
- Add Lower Bound for ``flaky`` Dependency (:pr:`4322` by `Palaptin <https://github.com/Palaptin>`_)
|
||||
- Bump ``pytest`` from 8.2.1 to 8.2.2 (:pr:`4294`)
|
||||
|
||||
Version 21.3
|
||||
============
|
||||
*Released 2024-06-07*
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
include LICENSE LICENSE.lesser requirements.txt requirements-opts.txt README_RAW.rst telegram/py.typed
|
||||
+51
-26
@@ -11,7 +11,7 @@
|
||||
:target: https://pypi.org/project/python-telegram-bot/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.4-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-8.1-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API version
|
||||
|
||||
@@ -66,23 +66,36 @@ We have a vibrant community of developers helping each other in our `Telegram gr
|
||||
*Stay tuned for library updates and new releases on our* `Telegram Channel <https://telegram.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Introduction
|
||||
============
|
||||
------------
|
||||
|
||||
This library provides a pure Python, asynchronous interface for the
|
||||
`Telegram Bot API <https://core.telegram.org/bots/api>`_.
|
||||
It's compatible with Python versions **3.8+**.
|
||||
It's compatible with Python versions **3.9+**.
|
||||
|
||||
In addition to the pure API implementation, this library features a number of high-level classes to
|
||||
In addition to the pure API implementation, this library features several convenience methods and shortcuts as well as a number of high-level classes to
|
||||
make the development of bots easy and straightforward. These classes are contained in the
|
||||
``telegram.ext`` submodule.
|
||||
|
||||
Telegram API support
|
||||
====================
|
||||
After installing_ the library, be sure to check out the section on `working with PTB`_.
|
||||
|
||||
All types and methods of the Telegram Bot API **7.4** are supported.
|
||||
Telegram API support
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All types and methods of the Telegram Bot API **8.1** are natively supported by this library.
|
||||
In addition, Bot API functionality not yet natively included can still be used as described `in our wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Bot-API-Forward-Compatibility>`_.
|
||||
|
||||
Notable Features
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
- `Fully asynchronous <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Concurrency>`_
|
||||
- Convenient shortcut methods, e.g. `Message.reply_text <https://docs.python-telegram-bot.org/en/stable/telegram.message.html#telegram.Message.reply_text>`_
|
||||
- `Fully annotated with static type hints <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Type-Checking>`_
|
||||
- `Customizable and extendable interface <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Architecture>`_
|
||||
- Seamless integration with `webhooks <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Webhooks>`_ and `polling <https://docs.python-telegram-bot.org/en/stable/telegram.ext.application.html#telegram.ext.Application.run_polling>`_
|
||||
- `Comprehensive documentation and examples <#working-with-ptb>`_
|
||||
|
||||
Installing
|
||||
==========
|
||||
----------
|
||||
|
||||
You can install or upgrade ``python-telegram-bot`` via
|
||||
|
||||
@@ -98,22 +111,27 @@ You can also install ``python-telegram-bot`` from source, though this is usually
|
||||
|
||||
$ git clone https://github.com/python-telegram-bot/python-telegram-bot
|
||||
$ cd python-telegram-bot
|
||||
$ python setup.py install
|
||||
$ pip install build
|
||||
$ python -m build
|
||||
|
||||
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``.
|
||||
To enable you to verify that a release file that you downloaded was indeed provided by the ``python-telegram-bot`` team, we have taken the following measures.
|
||||
|
||||
Starting with v21.4, all releases are signed via `sigstore <https://www.sigstore.dev>`_.
|
||||
The corresponding signature files are uploaded to the `GitHub releases page`_.
|
||||
To verify the signature, please install the `sigstore Python client <https://pypi.org/project/sigstore/>`_ and follow the instructions for `verifying signatures from GitHub Actions <https://github.com/sigstore/sigstore-python?tab=readme-ov-file>`_. As input for the ``--repository`` parameter, please use the value ``python-telegram-bot/python-telegram-bot``.
|
||||
|
||||
Earlier releases are signed with a GPG key.
|
||||
The signatures are uploaded to both the `GitHub releases page`_ 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.
|
||||
The keys are named in the format ``<first_version>-<last_version>.gpg``.
|
||||
|
||||
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
|
||||
-----------------------------
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``python-telegram-bot`` tries to use as few 3rd party dependencies as possible.
|
||||
However, for some features using a 3rd party library is more sane than implementing the functionality again.
|
||||
@@ -137,9 +155,9 @@ PTB can be installed with optional dependencies:
|
||||
* ``pip install "python-telegram-bot[passport]"`` installs the `cryptography>=39.0.1 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
|
||||
* ``pip install "python-telegram-bot[socks]"`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
|
||||
* ``pip install "python-telegram-bot[http2]"`` installs `httpx[http2] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to use HTTP/2.
|
||||
* ``pip install "python-telegram-bot[rate-limiter]"`` installs `aiolimiter~=1.1.0 <https://aiolimiter.readthedocs.io/en/stable/>`_. Use this, if you want to use ``telegram.ext.AIORateLimiter``.
|
||||
* ``pip install "python-telegram-bot[rate-limiter]"`` installs `aiolimiter~=1.1,<1.3 <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.4 <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.3 <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[callback-data]"`` installs the `cachetools>=5.3.3,<5.6.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.4 <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]"``.
|
||||
@@ -149,14 +167,19 @@ Additionally, two shortcuts are provided:
|
||||
* ``pip install "python-telegram-bot[all]"`` installs all optional dependencies.
|
||||
* ``pip install "python-telegram-bot[ext]"`` installs all optional dependencies that are related to ``telegram.ext``, i.e. ``[rate-limiter, webhooks, callback-data, job-queue]``.
|
||||
|
||||
Working with PTB
|
||||
----------------
|
||||
|
||||
Once you have installed the library, you can begin working with it - so let's get started!
|
||||
|
||||
Quick Start
|
||||
===========
|
||||
~~~~~~~~~~~
|
||||
|
||||
Our Wiki contains an `Introduction to the API <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Introduction-to-the-API>`_ explaining how the pure Bot API can be accessed via ``python-telegram-bot``.
|
||||
Moreover, the `Tutorial: Your first Bot <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions---Your-first-Bot>`_ gives an introduction on how chatbots can be easily programmed with the help of the ``telegram.ext`` module.
|
||||
|
||||
Resources
|
||||
=========
|
||||
~~~~~~~~~
|
||||
|
||||
- The `package documentation <https://docs.python-telegram-bot.org/>`_ is the technical reference for ``python-telegram-bot``.
|
||||
It contains descriptions of all available classes, modules, methods and arguments as well as the `changelog <https://docs.python-telegram-bot.org/changelog.html>`_.
|
||||
@@ -167,7 +190,7 @@ Resources
|
||||
- The `official Telegram Bot API documentation <https://core.telegram.org/bots/api>`_ is of course always worth a read.
|
||||
|
||||
Getting help
|
||||
============
|
||||
~~~~~~~~~~~~
|
||||
|
||||
If the resources mentioned above don't answer your questions or simply overwhelm you, there are several ways of getting help.
|
||||
|
||||
@@ -178,7 +201,7 @@ If the resources mentioned above don't answer your questions or simply overwhelm
|
||||
3. You can even ask for help on Stack Overflow using the `python-telegram-bot tag <https://stackoverflow.com/questions/tagged/python-telegram-bot>`_.
|
||||
|
||||
Concurrency
|
||||
===========
|
||||
~~~~~~~~~~~
|
||||
|
||||
Since v20.0, ``python-telegram-bot`` is built on top of Pythons ``asyncio`` module.
|
||||
Because ``asyncio`` is in general single-threaded, ``python-telegram-bot`` does currently not aim to be thread-safe.
|
||||
@@ -191,20 +214,22 @@ Noteworthy parts of ``python-telegram-bots`` API that are likely to cause issues
|
||||
* all classes in the ``telegram.ext.filters`` module that allow to add/remove allowed users/chats at runtime
|
||||
|
||||
Contributing
|
||||
============
|
||||
------------
|
||||
|
||||
Contributions of all sizes are welcome.
|
||||
Please review our `contribution guidelines <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.github/CONTRIBUTING.rst>`_ to get started.
|
||||
You can also help by `reporting bugs or feature requests <https://github.com/python-telegram-bot/python-telegram-bot/issues/new/choose>`_.
|
||||
|
||||
Donating
|
||||
========
|
||||
--------
|
||||
Occasionally we are asked if we accept donations to support the development.
|
||||
While we appreciate the thought, maintaining PTB is our hobby, and we have almost no running costs for it. We therefore have nothing set up to accept donations.
|
||||
If you still want to donate, we kindly ask you to donate to another open source project/initiative of your choice instead.
|
||||
|
||||
License
|
||||
=======
|
||||
-------
|
||||
|
||||
You may copy, distribute and modify the software provided that modifications are described and licensed for free under `LGPL-3 <https://www.gnu.org/licenses/lgpl-3.0.html>`_.
|
||||
Derivatives works (including modifications or anything statically linked to the library) can only be redistributed under LGPL-3, but applications that use the library don't have to be.
|
||||
Derivative works (including modifications or anything statically linked to the library) can only be redistributed under LGPL-3, but applications that use the library don't have to be.
|
||||
|
||||
.. _`GitHub releases page`: https://github.com/python-telegram-bot/python-telegram-bot/releases
|
||||
|
||||
-213
@@ -1,213 +0,0 @@
|
||||
.. image:: https://github.com/python-telegram-bot/logos/blob/master/logo-text/png/ptb-raw-logo-text_768.png?raw=true
|
||||
:align: center
|
||||
:target: https://python-telegram-bot.org
|
||||
:alt: python-telegram-bot-raw Logo
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/python-telegram-bot-raw.svg
|
||||
:target: https://pypi.org/project/python-telegram-bot-raw/
|
||||
:alt: PyPi Package Version
|
||||
|
||||
.. image:: https://img.shields.io/pypi/pyversions/python-telegram-bot-raw.svg
|
||||
:target: https://pypi.org/project/python-telegram-bot-raw/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.4-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API version
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/python-telegram-bot-raw
|
||||
:target: https://pypistats.org/packages/python-telegram-bot-raw
|
||||
:alt: PyPi Package Monthly Download
|
||||
|
||||
.. image:: https://readthedocs.org/projects/python-telegram-bot/badge/?version=stable
|
||||
:target: https://docs.python-telegram-bot.org/
|
||||
:alt: Documentation Status
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/python-telegram-bot-raw.svg
|
||||
:target: https://www.gnu.org/licenses/lgpl-3.0.html
|
||||
:alt: LGPLv3 License
|
||||
|
||||
.. image:: https://github.com/python-telegram-bot/python-telegram-bot/actions/workflows/unit_tests.yml/badge.svg?branch=master
|
||||
:target: https://github.com/python-telegram-bot/python-telegram-bot/
|
||||
:alt: Github Actions workflow
|
||||
|
||||
.. image:: https://codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg
|
||||
:target: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot
|
||||
:alt: Code coverage
|
||||
|
||||
.. image:: https://isitmaintained.com/badge/resolution/python-telegram-bot/python-telegram-bot.svg
|
||||
:target: https://isitmaintained.com/project/python-telegram-bot/python-telegram-bot
|
||||
:alt: Median time to resolve an issue
|
||||
|
||||
.. image:: https://api.codacy.com/project/badge/Grade/99d901eaa09b44b4819aec05c330c968
|
||||
:target: https://app.codacy.com/gh/python-telegram-bot/python-telegram-bot/dashboard
|
||||
:alt: Code quality: Codacy
|
||||
|
||||
.. image:: https://results.pre-commit.ci/badge/github/python-telegram-bot/python-telegram-bot/master.svg
|
||||
:target: https://results.pre-commit.ci/latest/github/python-telegram-bot/python-telegram-bot/master
|
||||
:alt: pre-commit.ci status
|
||||
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/psf/black
|
||||
:alt: Code Style: Black
|
||||
|
||||
.. image:: https://img.shields.io/badge/Telegram-Channel-blue.svg?logo=telegram
|
||||
:target: https://t.me/pythontelegrambotchannel
|
||||
:alt: Telegram Channel
|
||||
|
||||
.. image:: https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram
|
||||
:target: https://telegram.me/pythontelegrambotgroup
|
||||
:alt: Telegram Group
|
||||
|
||||
⚠️ Deprecation Notice
|
||||
=====================
|
||||
|
||||
The ``python-telegram-bot-raw`` library will no longer be updated after 21.3.
|
||||
Please instead use the ``python-telegram-bot`` `library <https://pypi.org/python-telegram-bot>`_.
|
||||
The change requires no changes in your code and requires no additional dependencies.
|
||||
For additional information, please see this `channel post <https://t.me/pythontelegrambotchannel/145>`_.
|
||||
|
||||
----
|
||||
|
||||
We have made you a wrapper you can't refuse
|
||||
|
||||
We have a vibrant community of developers helping each other in our `Telegram group <https://telegram.me/pythontelegrambotgroup>`_. Join us!
|
||||
|
||||
*Stay tuned for library updates and new releases on our* `Telegram Channel <https://telegram.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This library provides a pure Python, asynchronous interface for the
|
||||
`Telegram Bot API <https://core.telegram.org/bots/api>`_.
|
||||
It's compatible with Python versions **3.8+**.
|
||||
|
||||
``python-telegram-bot-raw`` is part of the `python-telegram-bot <https://python-telegram-bot.org>`_ ecosystem and provides the pure API functionality extracted from PTB. It therefore does not have independent release schedules, changelogs or documentation.
|
||||
|
||||
Note
|
||||
----
|
||||
|
||||
Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conjunction will result in undesired side-effects, so only install *one* of both.
|
||||
|
||||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **7.4** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
||||
You can install or upgrade ``python-telegram-bot`` via
|
||||
|
||||
.. code:: shell
|
||||
|
||||
$ pip install python-telegram-bot-raw --upgrade
|
||||
|
||||
To install a pre-release, use the ``--pre`` `flag <https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-pre>`_ in addition.
|
||||
|
||||
You can also install ``python-telegram-bot-raw`` from source, though this is usually not necessary.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
$ git clone https://github.com/python-telegram-bot/python-telegram-bot
|
||||
$ cd python-telegram-bot
|
||||
$ python setup_raw.py install
|
||||
|
||||
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
|
||||
-----------------------------
|
||||
|
||||
``python-telegram-bot`` tries to use as few 3rd party dependencies as possible.
|
||||
However, for some features using a 3rd party library is more sane than implementing the functionality again.
|
||||
As these features are *optional*, the corresponding 3rd party dependencies are not installed by default.
|
||||
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.27 <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.
|
||||
On the other hand, we have to ensure stability of ``python-telegram-bot``, which is why we do apply version bounds.
|
||||
If you encounter dependency conflicts due to these bounds, feel free to reach out.
|
||||
|
||||
Optional Dependencies
|
||||
#####################
|
||||
|
||||
PTB can be installed with optional dependencies:
|
||||
|
||||
* ``pip install "python-telegram-bot-raw[passport]"`` installs the `cryptography>=39.0.1 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
|
||||
* ``pip install "python-telegram-bot-raw[socks]"`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
|
||||
* ``pip install "python-telegram-bot-raw[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]"``.
|
||||
|
||||
Additionally, the shortcut ``pip install "python-telegram-bot-raw[all]"`` installs all optional dependencies.
|
||||
|
||||
Quick Start
|
||||
===========
|
||||
|
||||
Our Wiki contains an `Introduction to the API <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Introduction-to-the-API>`_ explaining how the pure Bot API can be accessed via ``python-telegram-bot``.
|
||||
|
||||
Resources
|
||||
=========
|
||||
|
||||
- The `package documentation <https://docs.python-telegram-bot.org/>`_ is the technical reference for ``python-telegram-bot``.
|
||||
It contains descriptions of all available classes, modules, methods and arguments as well as the `changelog <https://docs.python-telegram-bot.org/changelog.html>`_.
|
||||
- The `wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/>`_ is home to number of more elaborate introductions of the different features of ``python-telegram-bot`` and other useful resources that go beyond the technical documentation.
|
||||
- Our `examples section <https://docs.python-telegram-bot.org/examples.html>`_ contains several examples that showcase the different features of both the Bot API and ``python-telegram-bot``.
|
||||
Even if it is not your approach for learning, please take a look at ``echobot.py``. It is the de facto base for most of the bots out there.
|
||||
The code for these examples is released to the public domain, so you can start by grabbing the code and building on top of it.
|
||||
- The `official Telegram Bot API documentation <https://core.telegram.org/bots/api>`_ is of course always worth a read.
|
||||
|
||||
Getting help
|
||||
============
|
||||
|
||||
If the resources mentioned above don't answer your questions or simply overwhelm you, there are several ways of getting help.
|
||||
|
||||
1. We have a vibrant community of developers helping each other in our `Telegram group <https://telegram.me/pythontelegrambotgroup>`_. Join us! Asking a question here is often the quickest way to get a pointer in the right direction.
|
||||
|
||||
2. Ask questions by opening `a discussion <https://github.com/python-telegram-bot/python-telegram-bot/discussions/new>`_.
|
||||
|
||||
3. You can even ask for help on Stack Overflow using the `python-telegram-bot tag <https://stackoverflow.com/questions/tagged/python-telegram-bot>`_.
|
||||
|
||||
Concurrency
|
||||
===========
|
||||
|
||||
Since v20.0, ``python-telegram-bot`` is built on top of Pythons ``asyncio`` module.
|
||||
Because ``asyncio`` is in general single-threaded, ``python-telegram-bot`` does currently not aim to be thread-safe.
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
Contributions of all sizes are welcome.
|
||||
Please review our `contribution guidelines <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.github/CONTRIBUTING.rst>`_ to get started.
|
||||
You can also help by `reporting bugs or feature requests <https://github.com/python-telegram-bot/python-telegram-bot/issues/new/choose>`_.
|
||||
|
||||
Donating
|
||||
========
|
||||
Occasionally we are asked if we accept donations to support the development.
|
||||
While we appreciate the thought, maintaining PTB is our hobby, and we have almost no running costs for it. We therefore have nothing set up to accept donations.
|
||||
If you still want to donate, we kindly ask you to donate to another open source project/initiative of your choice instead.
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
You may copy, distribute and modify the software provided that modifications are described and licensed for free under `LGPL-3 <https://www.gnu.org/licenses/lgpl-3.0.html>`_.
|
||||
Derivatives works (including modifications or anything statically linked to the library) can only be redistributed under LGPL-3, but applications that use the library don't have to be.
|
||||
@@ -20,7 +20,8 @@ import inspect
|
||||
import re
|
||||
import typing
|
||||
from collections import defaultdict
|
||||
from typing import Any, Iterator, Union
|
||||
from collections.abc import Iterator
|
||||
from typing import Any, Union
|
||||
|
||||
import telegram
|
||||
import telegram.ext
|
||||
@@ -140,7 +141,7 @@ class AdmonitionInserter:
|
||||
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":(class|obj):`.+`" # 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.
|
||||
@@ -149,11 +150,11 @@ class AdmonitionInserter:
|
||||
)
|
||||
|
||||
# for properties: there is no attr name in docstring. Just check if there's a class name.
|
||||
prop_docstring_pattern = re.compile(r":class:`.+`.*:")
|
||||
prop_docstring_pattern = re.compile(r":(class|obj):`.+`.*:")
|
||||
|
||||
# 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.]*)`")
|
||||
single_class_name_pattern = re.compile(r":(class|obj):`~?(?P<class_name>[\w.]*)`")
|
||||
|
||||
classes_to_inspect = inspect.getmembers(telegram, inspect.isclass) + inspect.getmembers(
|
||||
telegram.ext, inspect.isclass
|
||||
@@ -366,6 +367,7 @@ class AdmonitionInserter:
|
||||
# to ".. admonition: Examples":
|
||||
".. admonition:: Examples",
|
||||
".. version",
|
||||
"Args:",
|
||||
# The space after ":param" is important because docstring can contain
|
||||
# ":paramref:" in its plain text in the beginning of a line (e.g. ExtBot):
|
||||
":param ",
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import inspect
|
||||
from typing import List
|
||||
|
||||
keyword_args = [
|
||||
"Keyword Arguments:",
|
||||
@@ -85,7 +84,7 @@ get_updates_read_timeout_addition = [
|
||||
]
|
||||
|
||||
|
||||
def find_insert_pos_for_kwargs(lines: List[str]) -> int:
|
||||
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"):
|
||||
|
||||
@@ -21,7 +21,6 @@ https://github.com/sphinx-doc/sphinx/issues/1556 is closed
|
||||
"""
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from sphinx.util import logging
|
||||
|
||||
@@ -32,7 +31,7 @@ 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: Dict[str, Tuple[Path, int, int]] = {}
|
||||
LINE_NUMBERS: dict[str, tuple[Path, int, int]] = {}
|
||||
|
||||
|
||||
def _git_branch() -> str:
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import collections.abc
|
||||
import contextlib
|
||||
import inspect
|
||||
import re
|
||||
import typing
|
||||
@@ -153,13 +154,11 @@ def autodoc_process_docstring(
|
||||
if isinstance(obj, telegram.ext.filters.BaseFilter):
|
||||
obj = obj.__class__
|
||||
|
||||
try:
|
||||
with contextlib.suppress(Exception):
|
||||
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
|
||||
@@ -188,6 +187,11 @@ def autodoc_process_bases(app, name, obj, option, bases: list) -> None:
|
||||
bases[idx] = ":class:`enum.IntEnum`"
|
||||
continue
|
||||
|
||||
if "FloatEnum" in base:
|
||||
bases[idx] = ":class:`enum.Enum`"
|
||||
bases.insert(0, ":class:`float`")
|
||||
continue
|
||||
|
||||
# Drop generics (at least for now)
|
||||
if base.endswith("]"):
|
||||
base = base.split("[", maxsplit=1)[0]
|
||||
|
||||
@@ -88,7 +88,6 @@ class TGConstXRefRole(PyXRefRole):
|
||||
refnode.rawsource,
|
||||
CONSTANTS_ROLE,
|
||||
)
|
||||
return title, target
|
||||
except Exception as exc:
|
||||
sphinx_logger.exception(
|
||||
"%s:%d: WARNING: Did not convert reference %s due to an exception.",
|
||||
@@ -98,3 +97,5 @@ class TGConstXRefRole(PyXRefRole):
|
||||
exc_info=exc,
|
||||
)
|
||||
return title, target
|
||||
else:
|
||||
return title, target
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
sphinx==7.3.7
|
||||
furo==2024.5.6
|
||||
sphinx==8.1.3
|
||||
furo==2024.8.6
|
||||
furo-sphinx-search @ git+https://github.com/harshil21/furo-sphinx-search@v0.2.0.1
|
||||
sphinx-paramlinks==0.6.0
|
||||
sphinxcontrib-mermaid==0.9.2
|
||||
sphinxcontrib-mermaid==1.0.0
|
||||
sphinx-copybutton==0.5.2
|
||||
sphinx-inline-tabs==2023.4.21
|
||||
# Temporary. See #4387
|
||||
sphinx-build-compatibility @ git+https://github.com/readthedocs/sphinx-build-compatibility.git@58aabc5f207c6c2421f23d3578adc0b14af57047
|
||||
|
||||
+14
-2
@@ -1,3 +1,4 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
@@ -29,7 +30,7 @@ version = telegram.__version__
|
||||
release = telegram.__version__
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
needs_sphinx = "6.1.3"
|
||||
needs_sphinx = "8.1.3"
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
@@ -47,6 +48,10 @@ extensions = [
|
||||
"sphinx_search.extension",
|
||||
]
|
||||
|
||||
# Temporary. See #4387
|
||||
if os.environ.get("READTHEDOCS", "") == "True":
|
||||
extensions.append("sphinx_build_compatibility.extension")
|
||||
|
||||
# For shorter links to Wiki in docstrings
|
||||
extlinks = {
|
||||
"wiki": ("https://github.com/python-telegram-bot/python-telegram-bot/wiki/%s", "%s"),
|
||||
@@ -251,7 +256,14 @@ htmlhelp_basename = "python-telegram-bot-doc"
|
||||
|
||||
# The base URL which points to the root of the HTML documentation. It is used to indicate the
|
||||
# location of document using The Canonical Link Relation. Default: ''.
|
||||
html_baseurl = "https://docs.python-telegram-bot.org"
|
||||
# Set canonical URL from the Read the Docs Domain
|
||||
html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "")
|
||||
|
||||
# Tell Jinja2 templates the build is running on Read the Docs
|
||||
html_context = {}
|
||||
if os.environ.get("READTHEDOCS", "") == "True":
|
||||
html_context["READTHEDOCS"] = True
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
- Used for sending documents
|
||||
* - :meth:`~telegram.Bot.send_game`
|
||||
- Used for sending a game
|
||||
* - :meth:`~telegram.Bot.send_gift`
|
||||
- Used for sending a gift
|
||||
* - :meth:`~telegram.Bot.send_invoice`
|
||||
- Used for sending an invoice
|
||||
* - :meth:`~telegram.Bot.send_location`
|
||||
@@ -33,6 +35,8 @@
|
||||
- Used for sending media grouped together
|
||||
* - :meth:`~telegram.Bot.send_message`
|
||||
- Used for sending text messages
|
||||
* - :meth:`~telegram.Bot.send_paid_media`
|
||||
- Used for sending paid media to channels
|
||||
* - :meth:`~telegram.Bot.send_photo`
|
||||
- Used for sending photos
|
||||
* - :meth:`~telegram.Bot.send_poll`
|
||||
@@ -149,6 +153,8 @@
|
||||
- Used for setting a chat title
|
||||
* - :meth:`~telegram.Bot.set_chat_description`
|
||||
- Used for setting the description of a chat
|
||||
* - :meth:`~telegram.Bot.set_user_emoji_status`
|
||||
- Used for setting the users status emoji
|
||||
* - :meth:`~telegram.Bot.pin_chat_message`
|
||||
- Used for pinning a message
|
||||
* - :meth:`~telegram.Bot.unpin_chat_message`
|
||||
@@ -353,7 +359,7 @@
|
||||
.. raw:: html
|
||||
|
||||
<details>
|
||||
<summary>Miscellaneous</summary>
|
||||
<summary>Payments and Stars</summary>
|
||||
|
||||
.. list-table::
|
||||
:align: left
|
||||
@@ -361,16 +367,39 @@
|
||||
|
||||
* - :meth:`~telegram.Bot.create_invoice_link`
|
||||
- Used to generate an HTTP link for an invoice
|
||||
* - :meth:`~telegram.Bot.edit_user_star_subscription`
|
||||
- Used for editing a user's star subscription
|
||||
* - :meth:`~telegram.Bot.get_star_transactions`
|
||||
- Used for obtaining the bot's Telegram Stars transactions
|
||||
* - :meth:`~telegram.Bot.refund_star_payment`
|
||||
- Used for refunding a payment in Telegram Stars
|
||||
|
||||
.. raw:: html
|
||||
|
||||
</details>
|
||||
<br>
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<details>
|
||||
<summary>Miscellaneous</summary>
|
||||
|
||||
.. list-table::
|
||||
:align: left
|
||||
:widths: 1 4
|
||||
|
||||
* - :meth:`~telegram.Bot.close`
|
||||
- Used for closing server instance when switching to another local server
|
||||
* - :meth:`~telegram.Bot.log_out`
|
||||
- Used for logging out from cloud Bot API server
|
||||
* - :meth:`~telegram.Bot.get_file`
|
||||
- Used for getting basic info about a file
|
||||
* - :meth:`~telegram.Bot.get_available_gifts`
|
||||
- Used for getting information about gifts available for sending
|
||||
* - :meth:`~telegram.Bot.get_me`
|
||||
- Used for getting basic information about the bot
|
||||
* - :meth:`~telegram.Bot.refund_star_payment`
|
||||
- Used for refunding a payment in Telegram Stars
|
||||
* - :meth:`~telegram.Bot.save_prepared_inline_message`
|
||||
- Used for storing a message to be sent by a user of a Mini App
|
||||
|
||||
.. raw:: html
|
||||
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<div style="display: none">
|
||||
|
||||
Hidden Headline
|
||||
===============
|
||||
This is just here to get furo to display the right sidebar.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
</div>
|
||||
|
||||
.. include:: ../../README.rst
|
||||
|
||||
.. The toctrees are hidden such that they don't render on the start page but still include the contents into the documentation.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
AffiliateInfo
|
||||
=============
|
||||
|
||||
.. autoclass:: telegram.AffiliateInfo
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -29,6 +29,7 @@ Available Types
|
||||
telegram.chat
|
||||
telegram.chatadministratorrights
|
||||
telegram.chatbackground
|
||||
telegram.copytextbutton
|
||||
telegram.backgroundtype
|
||||
telegram.backgroundtypefill
|
||||
telegram.backgroundtypewallpaper
|
||||
@@ -88,8 +89,10 @@ Available Types
|
||||
telegram.inputmediadocument
|
||||
telegram.inputmediaphoto
|
||||
telegram.inputmediavideo
|
||||
telegram.inputpaidmedia
|
||||
telegram.inputpaidmediaphoto
|
||||
telegram.inputpaidmediavideo
|
||||
telegram.inputpolloption
|
||||
telegram.inputsticker
|
||||
telegram.keyboardbutton
|
||||
telegram.keyboardbuttonpolltype
|
||||
telegram.keyboardbuttonrequestchat
|
||||
@@ -113,6 +116,12 @@ Available Types
|
||||
telegram.messageoriginuser
|
||||
telegram.messagereactioncountupdated
|
||||
telegram.messagereactionupdated
|
||||
telegram.paidmedia
|
||||
telegram.paidmediainfo
|
||||
telegram.paidmediaphoto
|
||||
telegram.paidmediapreview
|
||||
telegram.paidmediapurchased
|
||||
telegram.paidmediavideo
|
||||
telegram.photosize
|
||||
telegram.poll
|
||||
telegram.pollanswer
|
||||
@@ -122,6 +131,7 @@ Available Types
|
||||
telegram.reactiontype
|
||||
telegram.reactiontypecustomemoji
|
||||
telegram.reactiontypeemoji
|
||||
telegram.reactiontypepaid
|
||||
telegram.replykeyboardmarkup
|
||||
telegram.replykeyboardremove
|
||||
telegram.replyparameters
|
||||
|
||||
@@ -5,5 +5,5 @@ telegram.constants Module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:no-undoc-members:
|
||||
:inherited-members: Enum, EnumMeta, str, int
|
||||
:inherited-members: Enum, EnumMeta, str, int, float
|
||||
:exclude-members: __format__, __new__, __repr__, __str__
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
CopyTextButton
|
||||
==============
|
||||
|
||||
.. autoclass:: telegram.CopyTextButton
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -18,6 +18,7 @@ Handlers
|
||||
telegram.ext.inlinequeryhandler
|
||||
telegram.ext.messagehandler
|
||||
telegram.ext.messagereactionhandler
|
||||
telegram.ext.paidmediapurchasedhandler
|
||||
telegram.ext.pollanswerhandler
|
||||
telegram.ext.pollhandler
|
||||
telegram.ext.precheckoutqueryhandler
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
PaidMediaPurchasedHandler
|
||||
=========================
|
||||
|
||||
.. autoclass:: telegram.ext.PaidMediaPurchasedHandler
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -1,6 +1,21 @@
|
||||
.. _games-tree:
|
||||
|
||||
Games
|
||||
-----
|
||||
|
||||
Your bot can offer users **HTML5 games** to play solo or to compete against each other in groups and one-on-one chats. Create games via `@BotFather <https://telegram.me/BotFather>`_ using the ``/newgame`` command. Please note that this kind of power requires responsibility: you will need to accept the terms for each game that your bots will be offering.
|
||||
|
||||
* Games are a new type of content on Telegram, represented by the :class:`telegram.Game` and :class:`telegram.InlineQueryResultGame` objects.
|
||||
* Once you've created a game via `BotFather <https://t.me/botfather>`_, you can send games to chats as regular messages using the :meth:`~telegram.Bot.sendGame` method, or use :ref:`inline mode <inline-tree>` with :class:`telegram.InlineQueryResultGame`.
|
||||
* If you send the game message without any buttons, it will automatically have a 'Play ``GameName``' button. When this button is pressed, your bot gets a :class:`telegram.CallbackQuery` with the ``game_short_name`` of the requested game. You provide the correct URL for this particular user and the app opens the game in the in-app browser.
|
||||
* You can manually add multiple buttons to your game message. Please note that the first button in the first row **must always** launch the game, using the field ``callback_game`` in :class:`telegram.InlineKeyboardButton`. You can add extra buttons according to taste: e.g., for a description of the rules, or to open the game's official community.
|
||||
* To make your game more attractive, you can upload a GIF animation that demonstrates the game to the users via `BotFather <https://t.me/botfather>`_ (see `Lumberjack <https://t.me/gamebot?game=lumberjack>`_ for example).
|
||||
* A game message will also display high scores for the current chat. Use :meth:`~telegram.Bot.setGameScore` to post high scores to the chat with the game, add the :paramref:`~telegram.Bot.set_game_score.disable_edit_message` parameter to disable automatic update of the message with the current scoreboard.
|
||||
* Use :meth:`~telegram.Bot.getGameHighScores` to get data for in-game high score tables.
|
||||
* You can also add an extra sharing button for users to share their best score to different chats.
|
||||
* For examples of what can be done using this new stuff, check the `@gamebot <https://t.me/gamebot>`_ and `@gamee <https://t.me/gamee>`_ bots.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Gift
|
||||
====
|
||||
|
||||
.. autoclass:: telegram.Gift
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
Gifts
|
||||
=====
|
||||
|
||||
.. autoclass:: telegram.Gifts
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -1,6 +1,14 @@
|
||||
.. _inline-tree:
|
||||
|
||||
Inline Mode
|
||||
-----------
|
||||
|
||||
The following methods and objects allow your bot to work in `inline mode <https://core.telegram.org/bots/inline>`_.
|
||||
Please see Telegrams `Introduction to Inline bots <https://core.telegram.org/bots/inline>`_ for more details.
|
||||
|
||||
To enable this option, send the ``/setinline`` command to `@BotFather <https://t.me/botfather>`_ and provide the placeholder text that the user will see in the input field after typing your bot's name.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
@@ -34,3 +42,4 @@ Inline Mode
|
||||
telegram.inputvenuemessagecontent
|
||||
telegram.inputcontactmessagecontent
|
||||
telegram.inputinvoicemessagecontent
|
||||
telegram.preparedinlinemessage
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
InputPaidMedia
|
||||
==============
|
||||
|
||||
.. autoclass:: telegram.InputPaidMedia
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
InputPaidMediaPhoto
|
||||
===================
|
||||
|
||||
.. autoclass:: telegram.InputPaidMediaPhoto
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
InputPaidMediaVideo
|
||||
===================
|
||||
|
||||
.. autoclass:: telegram.InputPaidMediaVideo
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
PaidMedia
|
||||
=========
|
||||
|
||||
.. autoclass:: telegram.PaidMedia
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
PaidMediaInfo
|
||||
=============
|
||||
|
||||
.. autoclass:: telegram.PaidMediaInfo
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
PaidMediaPhoto
|
||||
==============
|
||||
|
||||
.. autoclass:: telegram.PaidMediaPhoto
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
PaidMediaPreview
|
||||
================
|
||||
|
||||
.. autoclass:: telegram.PaidMediaPreview
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
PaidMediaPurchased
|
||||
==================
|
||||
|
||||
.. autoclass:: telegram.PaidMediaPurchased
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
PaidMediaVideo
|
||||
==============
|
||||
|
||||
.. autoclass:: telegram.PaidMediaVideo
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -1,6 +1,9 @@
|
||||
Passport
|
||||
--------
|
||||
|
||||
Passport is a unified authorization method for services that require personal identification. Users can upload their documents once, then instantly share their data with services that require real-world ID (finance, ICOs, etc.). Please see the `manual <https://core.telegram.org/passport>`_ for details.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
|
||||
@@ -1,14 +1,34 @@
|
||||
.. _payments-tree:
|
||||
|
||||
Payments
|
||||
--------
|
||||
|
||||
Your bot can accept payments from Telegram users. Please see the `introduction to payments <https://core.telegram.org/bots/payments>`_ for more details on the process and how to set up payments for your bot.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
telegram.affiliateinfo
|
||||
telegram.invoice
|
||||
telegram.labeledprice
|
||||
telegram.orderinfo
|
||||
telegram.precheckoutquery
|
||||
telegram.refundedpayment
|
||||
telegram.revenuewithdrawalstate
|
||||
telegram.revenuewithdrawalstatefailed
|
||||
telegram.revenuewithdrawalstatepending
|
||||
telegram.revenuewithdrawalstatesucceeded
|
||||
telegram.shippingaddress
|
||||
telegram.shippingoption
|
||||
telegram.shippingquery
|
||||
telegram.startransaction
|
||||
telegram.startransactions
|
||||
telegram.successfulpayment
|
||||
telegram.transactionpartner
|
||||
telegram.transactionpartneraffiliateprogram
|
||||
telegram.transactionpartnerfragment
|
||||
telegram.transactionpartnerother
|
||||
telegram.transactionpartnertelegramads
|
||||
telegram.transactionpartnertelegramapi
|
||||
telegram.transactionpartneruser
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
PreparedInlineMessage
|
||||
=====================
|
||||
|
||||
.. autoclass:: telegram.PreparedInlineMessage
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
ReactionTypePaid
|
||||
================
|
||||
|
||||
.. autoclass:: telegram.ReactionTypePaid
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
RefundedPayment
|
||||
===============
|
||||
|
||||
.. autoclass:: telegram.RefundedPayment
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,7 @@
|
||||
RevenueWithdrawalState
|
||||
======================
|
||||
|
||||
.. autoclass:: telegram.RevenueWithdrawalState
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TelegramObject
|
||||
@@ -0,0 +1,7 @@
|
||||
RevenueWithdrawalStateFailed
|
||||
=============================
|
||||
|
||||
.. autoclass:: telegram.RevenueWithdrawalStateFailed
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TelegramObject
|
||||
@@ -0,0 +1,7 @@
|
||||
RevenueWithdrawalStatePending
|
||||
=============================
|
||||
|
||||
.. autoclass:: telegram.RevenueWithdrawalStatePending
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TelegramObject
|
||||
@@ -0,0 +1,7 @@
|
||||
RevenueWithdrawalStateSucceeded
|
||||
===============================
|
||||
|
||||
.. autoclass:: telegram.RevenueWithdrawalStateSucceeded
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TelegramObject
|
||||
@@ -0,0 +1,7 @@
|
||||
StarTransaction
|
||||
===============
|
||||
|
||||
.. autoclass:: telegram.StarTransaction
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TelegramObject
|
||||
@@ -0,0 +1,8 @@
|
||||
StarTransactions
|
||||
================
|
||||
|
||||
.. autoclass:: telegram.StarTransactions
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TelegramObject
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
Stickers
|
||||
--------
|
||||
|
||||
The following methods and objects allow your bot to handle stickers and sticker sets.
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
telegram.gift
|
||||
telegram.gifts
|
||||
telegram.inputsticker
|
||||
telegram.maskposition
|
||||
telegram.sticker
|
||||
telegram.stickerset
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
TransactionPartner
|
||||
==================
|
||||
|
||||
.. autoclass:: telegram.TransactionPartner
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TelegramObject
|
||||
@@ -0,0 +1,6 @@
|
||||
TransactionPartnerAffiliateProgram
|
||||
===================================
|
||||
|
||||
.. autoclass:: telegram.TransactionPartnerAffiliateProgram
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,7 @@
|
||||
TransactionPartnerFragment
|
||||
==========================
|
||||
|
||||
.. autoclass:: telegram.TransactionPartnerFragment
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TransactionPartner
|
||||
@@ -0,0 +1,7 @@
|
||||
TransactionPartnerOther
|
||||
=======================
|
||||
|
||||
.. autoclass:: telegram.TransactionPartnerOther
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TransactionPartner
|
||||
@@ -0,0 +1,7 @@
|
||||
TransactionPartnerTelegramAds
|
||||
=============================
|
||||
|
||||
.. autoclass:: telegram.TransactionPartnerTelegramAds
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TransactionPartner
|
||||
@@ -0,0 +1,7 @@
|
||||
TransactionPartnerTelegramApi
|
||||
=============================
|
||||
|
||||
.. autoclass:: telegram.TransactionPartnerTelegramApi
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TransactionPartner
|
||||
@@ -0,0 +1,7 @@
|
||||
TransactionPartnerUser
|
||||
======================
|
||||
|
||||
.. autoclass:: telegram.TransactionPartnerUser
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TransactionPartner
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
.. |editreplymarkup| replace:: It is currently only possible to edit messages without :attr:`telegram.Message.reply_markup` or with inline keyboards.
|
||||
|
||||
.. |bcid_edit_time| replace:: Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within *48 hours* from the time they were sent.
|
||||
|
||||
.. |toapikwargsbase| replace:: These arguments are also considered by :meth:`~telegram.TelegramObject.to_dict` and :meth:`~telegram.TelegramObject.to_json`, i.e. when passing objects to Telegram. Passing them to Telegram is however not guaranteed to work for all kinds of objects, e.g. this will fail for objects that can not directly be JSON serialized.
|
||||
|
||||
.. |toapikwargsarg| replace:: Arbitrary keyword arguments. Can be used to store data for which there are no dedicated attributes. |toapikwargsbase|
|
||||
@@ -58,10 +60,12 @@
|
||||
|
||||
.. |removed_thumb_note| replace:: Removed the deprecated argument and attribute ``thumb``.
|
||||
|
||||
.. |removed_thumb_url_note| replace:: Removed the deprecated argument and attribute ``thumb_url``.
|
||||
.. |removed_thumb_url_note| replace:: Removed the deprecated argument and attribute ``thumb_url`` which made thumbnail_url mandatory.
|
||||
|
||||
.. |removed_thumb_wildcard_note| replace:: Removed the deprecated arguments and attributes ``thumb_*``.
|
||||
|
||||
.. |thumbnail_url_mandatory| replace:: Removal of the deprecated argument ``thumb_url`` made ``thumbnail_url`` mandatory.
|
||||
|
||||
.. |async_context_manager| replace:: Asynchronous context manager which
|
||||
|
||||
.. |reply_parameters| replace:: Description of the message to reply to.
|
||||
@@ -82,8 +86,14 @@
|
||||
|
||||
.. |business_id_str| replace:: Unique identifier of the business connection on behalf of which the message will be sent.
|
||||
|
||||
.. |business_id_str_edit| replace:: Unique identifier of the business connection on behalf of which the message to be edited was sent
|
||||
|
||||
.. |message_effect_id| replace:: Unique identifier of the message effect to be added to the message; for private chats only.
|
||||
|
||||
.. |show_cap_above_med| replace:: :obj:`True`, if the caption must be shown above the message media.
|
||||
|
||||
.. |tg_stars| replace:: `Telegram Stars <https://t.me/BotNews/90>`__
|
||||
|
||||
.. |allow_paid_broadcast| replace:: Pass True to allow up to :tg-const:`telegram.constants.FloodLimit.PAID_MESSAGES_PER_SECOND` messages per second, ignoring `broadcasting limits <https://core.telegram.org/bots/faq#how-can-i-message-all-of-my-bot-39s-subscribers-at-once>`__ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance.
|
||||
|
||||
.. |tz-naive-dtms| replace:: For timezone naive :obj:`datetime.datetime` objects, the default timezone of the bot will be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used.
|
||||
@@ -12,7 +12,7 @@ To use arbitrary callback data, you must install PTB via
|
||||
`pip install "python-telegram-bot[callback-data]"`
|
||||
"""
|
||||
import logging
|
||||
from typing import List, Tuple, cast
|
||||
from typing import cast
|
||||
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
||||
from telegram.ext import (
|
||||
@@ -36,7 +36,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Sends a message with 5 inline buttons attached."""
|
||||
number_list: List[int] = []
|
||||
number_list: list[int] = []
|
||||
await update.message.reply_text("Please choose:", reply_markup=build_keyboard(number_list))
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ async def clear(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
await update.effective_message.reply_text("All clear!")
|
||||
|
||||
|
||||
def build_keyboard(current_list: List[int]) -> InlineKeyboardMarkup:
|
||||
def build_keyboard(current_list: list[int]) -> InlineKeyboardMarkup:
|
||||
"""Helper function to build the next inline keyboard."""
|
||||
return InlineKeyboardMarkup.from_column(
|
||||
[InlineKeyboardButton(str(i), callback_data=(i, current_list)) for i in range(1, 6)]
|
||||
@@ -69,7 +69,7 @@ async def list_button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> Non
|
||||
# Get the data from the callback_data.
|
||||
# If you're using a type checker like MyPy, you'll have to use typing.cast
|
||||
# to make the checker get the expected type of the callback_data
|
||||
number, number_list = cast(Tuple[int, List[int]], query.data)
|
||||
number, number_list = cast(tuple[int, list[int]], query.data)
|
||||
# append the number to the list
|
||||
number_list.append(number)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ bot.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional, Tuple
|
||||
from typing import Optional
|
||||
|
||||
from telegram import Chat, ChatMember, ChatMemberUpdated, Update
|
||||
from telegram.constants import ParseMode
|
||||
@@ -37,7 +37,7 @@ logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def extract_status_change(chat_member_update: ChatMemberUpdated) -> Optional[Tuple[bool, bool]]:
|
||||
def extract_status_change(chat_member_update: ChatMemberUpdated) -> Optional[tuple[bool, bool]]:
|
||||
"""Takes a ChatMemberUpdated instance and extracts whether the 'old_chat_member' was a member
|
||||
of the chat and whether the 'new_chat_member' is a member of the chat. Returns None, if
|
||||
the status didn't change.
|
||||
|
||||
@@ -12,7 +12,7 @@ bot.
|
||||
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
from typing import DefaultDict, Optional, Set
|
||||
from typing import Optional
|
||||
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
||||
from telegram.constants import ParseMode
|
||||
@@ -40,7 +40,7 @@ class ChatData:
|
||||
"""Custom class for chat_data. Here we store data per message."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.clicks_per_message: DefaultDict[int, int] = defaultdict(int)
|
||||
self.clicks_per_message: defaultdict[int, int] = defaultdict(int)
|
||||
|
||||
|
||||
# The [ExtBot, dict, ChatData, dict] is for type checkers like mypy
|
||||
@@ -57,7 +57,7 @@ class CustomContext(CallbackContext[ExtBot, dict, ChatData, dict]):
|
||||
self._message_id: Optional[int] = None
|
||||
|
||||
@property
|
||||
def bot_user_ids(self) -> Set[int]:
|
||||
def bot_user_ids(self) -> set[int]:
|
||||
"""Custom shortcut to access a value stored in the bot_data dict"""
|
||||
return self.bot_data.setdefault("user_ids", set())
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ bot.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Dict
|
||||
|
||||
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update
|
||||
from telegram.ext import (
|
||||
@@ -46,7 +45,7 @@ reply_keyboard = [
|
||||
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
|
||||
|
||||
|
||||
def facts_to_str(user_data: Dict[str, str]) -> str:
|
||||
def facts_to_str(user_data: dict[str, str]) -> str:
|
||||
"""Helper function for formatting the gathered user info."""
|
||||
facts = [f"{key} - {value}" for key, value in user_data.items()]
|
||||
return "\n".join(facts).join(["\n", "\n"])
|
||||
|
||||
@@ -15,7 +15,7 @@ bot.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Any, Dict, Tuple
|
||||
from typing import Any
|
||||
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
||||
from telegram.ext import (
|
||||
@@ -66,7 +66,7 @@ END = ConversationHandler.END
|
||||
|
||||
|
||||
# Helper
|
||||
def _name_switcher(level: str) -> Tuple[str, str]:
|
||||
def _name_switcher(level: str) -> tuple[str, str]:
|
||||
if level == PARENTS:
|
||||
return "Father", "Mother"
|
||||
return "Brother", "Sister"
|
||||
@@ -122,7 +122,7 @@ async def adding_self(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str
|
||||
async def show_data(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
|
||||
"""Pretty print gathered data."""
|
||||
|
||||
def pretty_print(data: Dict[str, Any], level: str) -> str:
|
||||
def pretty_print(data: dict[str, Any], level: str) -> str:
|
||||
people = data.get(level)
|
||||
if not people:
|
||||
return "\nNo information yet."
|
||||
@@ -371,8 +371,8 @@ def main() -> None:
|
||||
entry_points=[CommandHandler("start", start)],
|
||||
states={
|
||||
SHOWING: [CallbackQueryHandler(start, pattern="^" + str(END) + "$")],
|
||||
SELECTING_ACTION: selection_handlers,
|
||||
SELECTING_LEVEL: selection_handlers,
|
||||
SELECTING_ACTION: selection_handlers, # type: ignore[dict-item]
|
||||
SELECTING_LEVEL: selection_handlers, # type: ignore[dict-item]
|
||||
DESCRIBING_SELF: [description_conv],
|
||||
STOPPING: [CommandHandler("start", start)],
|
||||
},
|
||||
|
||||
+10
-10
@@ -47,9 +47,9 @@ async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
# Files will be downloaded to current directory
|
||||
for data in passport_data.decrypted_data: # This is where the data gets decrypted
|
||||
if data.type == "phone_number":
|
||||
print("Phone: ", data.phone_number)
|
||||
logger.info("Phone: %s", data.phone_number)
|
||||
elif data.type == "email":
|
||||
print("Email: ", data.email)
|
||||
logger.info("Email: %s", data.email)
|
||||
if data.type in (
|
||||
"personal_details",
|
||||
"passport",
|
||||
@@ -58,7 +58,7 @@ async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"internal_passport",
|
||||
"address",
|
||||
):
|
||||
print(data.type, data.data)
|
||||
logger.info(data.type, data.data)
|
||||
if data.type in (
|
||||
"utility_bill",
|
||||
"bank_statement",
|
||||
@@ -66,28 +66,28 @@ async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"passport_registration",
|
||||
"temporary_registration",
|
||||
):
|
||||
print(data.type, len(data.files), "files")
|
||||
logger.info(data.type, len(data.files), "files")
|
||||
for file in data.files:
|
||||
actual_file = await file.get_file()
|
||||
print(actual_file)
|
||||
logger.info(actual_file)
|
||||
await actual_file.download_to_drive()
|
||||
if (
|
||||
data.type in ("passport", "driver_license", "identity_card", "internal_passport")
|
||||
and data.front_side
|
||||
):
|
||||
front_file = await data.front_side.get_file()
|
||||
print(data.type, front_file)
|
||||
logger.info(data.type, front_file)
|
||||
await front_file.download_to_drive()
|
||||
if data.type in ("driver_license" and "identity_card") and data.reverse_side:
|
||||
reverse_file = await data.reverse_side.get_file()
|
||||
print(data.type, reverse_file)
|
||||
logger.info(data.type, reverse_file)
|
||||
await reverse_file.download_to_drive()
|
||||
if (
|
||||
data.type in ("passport", "driver_license", "identity_card", "internal_passport")
|
||||
and data.selfie
|
||||
):
|
||||
selfie_file = await data.selfie.get_file()
|
||||
print(data.type, selfie_file)
|
||||
logger.info(data.type, selfie_file)
|
||||
await selfie_file.download_to_drive()
|
||||
if data.translation and data.type in (
|
||||
"passport",
|
||||
@@ -100,10 +100,10 @@ async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"passport_registration",
|
||||
"temporary_registration",
|
||||
):
|
||||
print(data.type, len(data.translation), "translation")
|
||||
logger.info(data.type, len(data.translation), "translation")
|
||||
for file in data.translation:
|
||||
actual_file = await file.get_file()
|
||||
print(actual_file)
|
||||
logger.info(actual_file)
|
||||
await actual_file.download_to_drive()
|
||||
|
||||
|
||||
|
||||
+39
-40
@@ -2,7 +2,7 @@
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""Basic example for a bot that can receive payment from user."""
|
||||
"""Basic example for a bot that can receive payments from users."""
|
||||
|
||||
import logging
|
||||
|
||||
@@ -26,36 +26,36 @@ logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Insert the token from your payment provider.
|
||||
# In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
|
||||
PAYMENT_PROVIDER_TOKEN = "PAYMENT_PROVIDER_TOKEN"
|
||||
|
||||
|
||||
async def start_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Displays info on how to use the bot."""
|
||||
"""Provides instructions on how to use the bot."""
|
||||
msg = (
|
||||
"Use /shipping to get an invoice for shipping-payment, or /noshipping for an "
|
||||
"Use /shipping to receive an invoice with shipping included, or /noshipping for an "
|
||||
"invoice without shipping."
|
||||
)
|
||||
|
||||
await update.message.reply_text(msg)
|
||||
|
||||
|
||||
async def start_with_shipping_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Sends an invoice with shipping-payment."""
|
||||
"""Sends an invoice which triggers a shipping query."""
|
||||
chat_id = update.message.chat_id
|
||||
title = "Payment Example"
|
||||
description = "Payment Example using python-telegram-bot"
|
||||
# select a payload just for you to recognize its the donation from your bot
|
||||
description = "Example of a payment process using the python-telegram-bot library."
|
||||
# Unique payload to identify this payment request as being from your bot
|
||||
payload = "Custom-Payload"
|
||||
# In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
|
||||
# Set up the currency.
|
||||
# List of supported currencies: https://core.telegram.org/bots/payments#supported-currencies
|
||||
currency = "USD"
|
||||
# price in dollars
|
||||
# Price in dollars
|
||||
price = 1
|
||||
# price * 100 so as to include 2 decimal points
|
||||
# check https://core.telegram.org/bots/payments#supported-currencies for more details
|
||||
# Convert price to cents from dollars.
|
||||
prices = [LabeledPrice("Test", price * 100)]
|
||||
|
||||
# optionally pass need_name=True, need_phone_number=True,
|
||||
# need_email=True, need_shipping_address=True, is_flexible=True
|
||||
# Optional parameters like need_shipping_address and is_flexible trigger extra user prompts
|
||||
# https://docs.python-telegram-bot.org/en/stable/telegram.bot.html#telegram.Bot.send_invoice
|
||||
await context.bot.send_invoice(
|
||||
chat_id,
|
||||
title,
|
||||
@@ -75,17 +75,16 @@ async def start_with_shipping_callback(update: Update, context: ContextTypes.DEF
|
||||
async def start_without_shipping_callback(
|
||||
update: Update, context: ContextTypes.DEFAULT_TYPE
|
||||
) -> None:
|
||||
"""Sends an invoice without shipping-payment."""
|
||||
"""Sends an invoice without requiring shipping details."""
|
||||
chat_id = update.message.chat_id
|
||||
title = "Payment Example"
|
||||
description = "Payment Example using python-telegram-bot"
|
||||
# select a payload just for you to recognize its the donation from your bot
|
||||
description = "Example of a payment process using the python-telegram-bot library."
|
||||
# Unique payload to identify this payment request as being from your bot
|
||||
payload = "Custom-Payload"
|
||||
# In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
|
||||
currency = "USD"
|
||||
# price in dollars
|
||||
# Price in dollars
|
||||
price = 1
|
||||
# price * 100 so as to include 2 decimal points
|
||||
# Convert price to cents from dollars.
|
||||
prices = [LabeledPrice("Test", price * 100)]
|
||||
|
||||
# optionally pass need_name=True, need_phone_number=True,
|
||||
@@ -96,65 +95,65 @@ async def start_without_shipping_callback(
|
||||
|
||||
|
||||
async def shipping_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Answers the ShippingQuery with ShippingOptions"""
|
||||
"""Handles the ShippingQuery with available shipping options."""
|
||||
query = update.shipping_query
|
||||
# check the payload, is this from your bot?
|
||||
# Verify if the payload matches, ensure it's from your bot
|
||||
if query.invoice_payload != "Custom-Payload":
|
||||
# answer False pre_checkout_query
|
||||
# If not, respond with an error
|
||||
await query.answer(ok=False, error_message="Something went wrong...")
|
||||
return
|
||||
|
||||
# First option has a single LabeledPrice
|
||||
# Define available shipping options
|
||||
# First option with a single price entry
|
||||
options = [ShippingOption("1", "Shipping Option A", [LabeledPrice("A", 100)])]
|
||||
# second option has an array of LabeledPrice objects
|
||||
# Second option with multiple price entries
|
||||
price_list = [LabeledPrice("B1", 150), LabeledPrice("B2", 200)]
|
||||
options.append(ShippingOption("2", "Shipping Option B", price_list))
|
||||
await query.answer(ok=True, shipping_options=options)
|
||||
|
||||
|
||||
# after (optional) shipping, it's the pre-checkout
|
||||
# After (optional) shipping, process the pre-checkout step
|
||||
async def precheckout_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Answers the PreQecheckoutQuery"""
|
||||
"""Responds to the PreCheckoutQuery as the final confirmation for checkout."""
|
||||
query = update.pre_checkout_query
|
||||
# check the payload, is this from your bot?
|
||||
# Verify if the payload matches, ensure it's from your bot
|
||||
if query.invoice_payload != "Custom-Payload":
|
||||
# answer False pre_checkout_query
|
||||
# If not, respond with an error
|
||||
await query.answer(ok=False, error_message="Something went wrong...")
|
||||
else:
|
||||
await query.answer(ok=True)
|
||||
|
||||
|
||||
# finally, after contacting the payment provider...
|
||||
# Final callback after successful payment
|
||||
async def successful_payment_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Confirms the successful payment."""
|
||||
# do something after successfully receiving payment?
|
||||
await update.message.reply_text("Thank you for your payment!")
|
||||
"""Acknowledges successful payment and thanks the user."""
|
||||
await update.message.reply_text("Thank you for your payment.")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Run the bot."""
|
||||
"""Starts the bot and sets up handlers."""
|
||||
# Create the Application and pass it your bot's token.
|
||||
application = Application.builder().token("TOKEN").build()
|
||||
|
||||
# simple start function
|
||||
# Start command to display usage instructions
|
||||
application.add_handler(CommandHandler("start", start_callback))
|
||||
|
||||
# Add command handler to start the payment invoice
|
||||
# Command handlers for starting the payment process
|
||||
application.add_handler(CommandHandler("shipping", start_with_shipping_callback))
|
||||
application.add_handler(CommandHandler("noshipping", start_without_shipping_callback))
|
||||
|
||||
# Optional handler if your product requires shipping
|
||||
# Handler for shipping query (if product requires shipping)
|
||||
application.add_handler(ShippingQueryHandler(shipping_callback))
|
||||
|
||||
# Pre-checkout handler to final check
|
||||
# Pre-checkout handler for verifying payment details.
|
||||
application.add_handler(PreCheckoutQueryHandler(precheckout_callback))
|
||||
|
||||
# Success! Notify your user!
|
||||
# Handler for successful payment. Notify the user that the payment was successful.
|
||||
application.add_handler(
|
||||
MessageHandler(filters.SUCCESSFUL_PAYMENT, successful_payment_callback)
|
||||
)
|
||||
|
||||
# Run the bot until the user presses Ctrl-C
|
||||
# Start polling for updates until interrupted (CTRL+C)
|
||||
application.run_polling(allowed_updates=Update.ALL_TYPES)
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ bot.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Dict
|
||||
|
||||
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update
|
||||
from telegram.ext import (
|
||||
@@ -47,7 +46,7 @@ reply_keyboard = [
|
||||
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
|
||||
|
||||
|
||||
def facts_to_str(user_data: Dict[str, str]) -> str:
|
||||
def facts_to_str(user_data: dict[str, str]) -> str:
|
||||
"""Helper function for formatting the gathered user info."""
|
||||
facts = [f"{key} - {value}" for key, value in user_data.items()]
|
||||
return "\n".join(facts).join(["\n", "\n"])
|
||||
|
||||
+124
-10
@@ -1,7 +1,115 @@
|
||||
# PACKAGING
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
dynamic = ["version"]
|
||||
name = "python-telegram-bot"
|
||||
description = "We have made you a wrapper you can't refuse"
|
||||
readme = "README.rst"
|
||||
requires-python = ">=3.9"
|
||||
license = "LGPL-3.0-only"
|
||||
license-files = { paths = ["LICENSE", "LICENSE.dual", "LICENSE.lesser"] }
|
||||
authors = [
|
||||
{ name = "Leandro Toledo", email = "devs@python-telegram-bot.org" }
|
||||
]
|
||||
keywords = [
|
||||
"python",
|
||||
"telegram",
|
||||
"bot",
|
||||
"api",
|
||||
"wrapper",
|
||||
]
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
|
||||
"Operating System :: OS Independent",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: Communications :: Chat",
|
||||
"Topic :: Internet",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
]
|
||||
dependencies = [
|
||||
"httpx ~= 0.27",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "https://python-telegram-bot.org"
|
||||
"Documentation" = "https://docs.python-telegram-bot.org"
|
||||
"Bug Tracker" = "https://github.com/python-telegram-bot/python-telegram-bot/issues"
|
||||
"Source Code" = "https://github.com/python-telegram-bot/python-telegram-bot"
|
||||
"News" = "https://t.me/pythontelegrambotchannel"
|
||||
"Changelog" = "https://docs.python-telegram-bot.org/en/stable/changelog.html"
|
||||
"Support" = "https://t.me/pythontelegrambotgroup"
|
||||
|
||||
[project.optional-dependencies]
|
||||
# Make sure to install those as additional_dependencies in the
|
||||
# pre-commit hooks for pylint & mypy
|
||||
# Also update the readme accordingly
|
||||
#
|
||||
# When dependencies release new versions and tests succeed, we should try to expand the allowed
|
||||
# versions and only increase the lower bound if necessary
|
||||
#
|
||||
# When adding new groups, make sure to update `ext` and `all` accordingly
|
||||
|
||||
# Optional dependencies for production
|
||||
all = [
|
||||
"python-telegram-bot[ext,http2,passport,socks]",
|
||||
]
|
||||
callback-data = [
|
||||
# Cachetools doesn't have a strict stability policy. Let's be cautious for now.
|
||||
"cachetools>=5.3.3,<5.6.0",
|
||||
]
|
||||
ext = [
|
||||
"python-telegram-bot[callback-data,job-queue,rate-limiter,webhooks]",
|
||||
]
|
||||
http2 = [
|
||||
"httpx[http2]",
|
||||
]
|
||||
job-queue = [
|
||||
# APS doesn't have a strict stability policy. Let's be cautious for now.
|
||||
"APScheduler~=3.10.4",
|
||||
# pytz is required by APS and just needs the lower bound due to #2120
|
||||
"pytz>=2018.6",
|
||||
]
|
||||
passport = [
|
||||
"cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=39.0.1",
|
||||
# cffi is a dependency of cryptography and added support for python 3.13 in 1.17.0rc1
|
||||
"cffi >= 1.17.0rc1; python_version > '3.12'"
|
||||
]
|
||||
rate-limiter = [
|
||||
"aiolimiter>=1.1,<1.3",
|
||||
]
|
||||
socks = [
|
||||
"httpx[socks]",
|
||||
]
|
||||
webhooks = [
|
||||
# tornado is rather stable, but let's not allow the next major release without prior testing
|
||||
"tornado~=6.4",
|
||||
]
|
||||
|
||||
|
||||
# HATCH
|
||||
[tool.hatch.version]
|
||||
# dynamically evaluates the `__version__` variable in that file
|
||||
source = "code"
|
||||
path = "telegram/_version.py"
|
||||
search-paths = ["telegram"]
|
||||
|
||||
[tool.hatch.build]
|
||||
packages = ["telegram"]
|
||||
|
||||
# BLACK:
|
||||
[tool.black]
|
||||
line-length = 99
|
||||
target-version = ['py38', 'py39', 'py310', 'py311']
|
||||
|
||||
# ISORT:
|
||||
[tool.isort] # black config
|
||||
@@ -11,24 +119,29 @@ line_length = 99
|
||||
# RUFF:
|
||||
[tool.ruff]
|
||||
line-length = 99
|
||||
target-version = "py38"
|
||||
show-fixes = true
|
||||
|
||||
[tool.ruff.lint]
|
||||
preview = true
|
||||
explicit-preview-rules = true
|
||||
explicit-preview-rules = true # TODO: Drop this when RUF022 and RUF023 are out of preview
|
||||
ignore = ["PLR2004", "PLR0911", "PLR0912", "PLR0913", "PLR0915", "PERF203"]
|
||||
select = ["E", "F", "I", "PL", "UP", "RUF", "PTH", "C4", "B", "PIE", "SIM", "RET", "RSE",
|
||||
"G", "ISC", "PT", "ASYNC", "TCH", "SLOT", "PERF", "PYI", "FLY", "AIR", "RUF022",
|
||||
"RUF023", "Q", "INP", "W", "YTT", "DTZ", "ARG"]
|
||||
# Add "FURB" after it's out of preview
|
||||
"RUF023", "Q", "INP", "W", "YTT", "DTZ", "ARG", "T20", "FURB", "DOC", "TRY",
|
||||
"D100", "D101", "D102", "D103", "D300", "D418", "D419", "S"]
|
||||
# Add "A (flake8-builtins)" after we drop pylint
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"tests/*.py" = ["B018"]
|
||||
"tests/**.py" = ["RUF012", "ASYNC101", "DTZ", "ARG"]
|
||||
"docs/**.py" = ["INP001", "ARG"]
|
||||
"examples/**.py" = ["ARG"]
|
||||
"tests/**.py" = ["RUF012", "ASYNC230", "DTZ", "ARG", "T201", "ASYNC109", "D", "S", "TRY"]
|
||||
"telegram/**.py" = ["TRY003"]
|
||||
"telegram/ext/_applicationbuilder.py" = ["TRY004"]
|
||||
"telegram/ext/filters.py" = ["D102"]
|
||||
"docs/**.py" = ["INP001", "ARG", "D", "TRY003", "S"]
|
||||
"examples/**.py" = ["ARG", "D", "S105", "TRY003"]
|
||||
|
||||
[tool.ruff.lint.pydocstyle]
|
||||
convention = "google"
|
||||
|
||||
# PYLINT:
|
||||
[tool.pylint."messages control"]
|
||||
@@ -36,7 +149,8 @@ enable = ["useless-suppression"]
|
||||
disable = ["duplicate-code", "too-many-arguments", "too-many-public-methods",
|
||||
"too-few-public-methods", "broad-exception-caught", "too-many-instance-attributes",
|
||||
"fixme", "missing-function-docstring", "missing-class-docstring", "too-many-locals",
|
||||
"too-many-lines", "too-many-branches", "too-many-statements", "cyclic-import"
|
||||
"too-many-lines", "too-many-branches", "too-many-statements", "cyclic-import",
|
||||
"too-many-positional-arguments",
|
||||
]
|
||||
|
||||
[tool.pylint.main]
|
||||
@@ -78,7 +192,7 @@ disallow_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
disallow_untyped_decorators = true
|
||||
show_error_codes = true
|
||||
python_version = "3.8"
|
||||
python_version = "3.9"
|
||||
|
||||
# For some files, it's easier to just disable strict-optional all together instead of
|
||||
# cluttering the code with `# type: ignore`s or stuff like
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
-r requirements.txt
|
||||
-r requirements-dev.txt
|
||||
-r requirements-opts.txt
|
||||
-r docs/requirements-docs.txt
|
||||
@@ -0,0 +1,5 @@
|
||||
-e .[all]
|
||||
# needed for pre-commit hooks in the git commit command
|
||||
pre-commit
|
||||
-r requirements-unit-tests.txt
|
||||
-r docs/requirements-docs.txt
|
||||
@@ -1,11 +0,0 @@
|
||||
pre-commit # needed for pre-commit hooks in the git commit command
|
||||
|
||||
# For the test suite
|
||||
setuptools # required for test_meta
|
||||
pytest==8.2.1
|
||||
pytest-asyncio==0.21.2 # needed because pytest doesn't come with native support for coroutines as tests
|
||||
pytest-xdist==3.6.1 # xdist runs tests in parallel
|
||||
flaky # Used for flaky tests (flaky decorator)
|
||||
beautifulsoup4 # used in test_official for parsing tg docs
|
||||
|
||||
wheel # required for building the wheels for releases
|
||||
@@ -1,27 +0,0 @@
|
||||
# Format:
|
||||
# package_name==version # req-1, req-2, req-3!ext
|
||||
# `pip install ptb-raw[req-1/2]` will install `package_name`
|
||||
# `pip install ptb[req-1/2/3]` will also install `package_name`
|
||||
|
||||
# Make sure to install those as additional_dependencies in the
|
||||
# pre-commit hooks for pylint & mypy
|
||||
# Also update the readme accordingly
|
||||
|
||||
# When dependencies release new versions and tests succeed, we should try to expand the allowed
|
||||
# versions and only increase the lower bound if necessary
|
||||
|
||||
httpx[socks] # socks
|
||||
httpx[http2] # http2
|
||||
cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=39.0.1 # passport
|
||||
aiolimiter~=1.1.0 # rate-limiter!ext
|
||||
|
||||
# tornado is rather stable, but let's not allow the next mayor release without prior testing
|
||||
tornado~=6.4 # webhooks!ext
|
||||
|
||||
# Cachetools and APS don't have a strict stability policy.
|
||||
# Let's be cautious for now.
|
||||
cachetools~=5.3.3 # callback-data!ext
|
||||
APScheduler~=3.10.4 # job-queue!ext
|
||||
|
||||
# pytz is required by APS and just needs the lower bound due to #2120
|
||||
pytz>=2018.6 # job-queue!ext
|
||||
@@ -0,0 +1,19 @@
|
||||
-e .
|
||||
|
||||
# required for building the wheels for releases
|
||||
build
|
||||
|
||||
# For the test suite
|
||||
pytest==8.3.4
|
||||
|
||||
# needed because pytest doesn't come with native support for coroutines as tests
|
||||
pytest-asyncio==0.21.2
|
||||
|
||||
# xdist runs tests in parallel
|
||||
pytest-xdist==3.6.1
|
||||
|
||||
# Used for flaky tests (flaky decorator)
|
||||
flaky>=3.8.1
|
||||
|
||||
# used in test_official for parsing tg docs
|
||||
beautifulsoup4
|
||||
@@ -1,10 +0,0 @@
|
||||
# Make sure to install those as additional_dependencies in the
|
||||
# pre-commit hooks for pylint & mypy
|
||||
# Also update the readme accordingly
|
||||
|
||||
# When dependencies release new versions and tests succeed, we should try to expand the allowed
|
||||
# versions and only increase the lower bound if necessary
|
||||
|
||||
# httpx has no stable release yet, but we've had no stability problems since v20.0a0 either
|
||||
# Since there have been requests to relax the bound a bit, we allow versions < 1.0.0
|
||||
httpx ~= 0.27
|
||||
@@ -1,8 +1,5 @@
|
||||
[metadata]
|
||||
license_files = LICENSE, LICENSE.dual, LICENSE.lesser
|
||||
|
||||
[flake8]
|
||||
max-line-length = 99
|
||||
ignore = W503, W605
|
||||
extend-ignore = E203, E704
|
||||
exclude = setup.py, setup_raw.py docs/source/conf.py
|
||||
exclude = docs/source/conf.py
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""The setup and build script for the python-telegram-bot library."""
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
|
||||
def get_requirements() -> List[str]:
|
||||
"""Build the requirements list for this project"""
|
||||
requirements_list = []
|
||||
|
||||
with Path("requirements.txt").open(encoding="utf-8") as reqs:
|
||||
for install in reqs:
|
||||
if install.startswith("#"):
|
||||
continue
|
||||
requirements_list.append(install.strip())
|
||||
|
||||
return requirements_list
|
||||
|
||||
|
||||
def get_packages_requirements(raw: bool = False) -> Tuple[List[str], List[str]]:
|
||||
"""Build the package & requirements list for this project"""
|
||||
reqs = get_requirements()
|
||||
|
||||
exclude = ["tests*", "docs*"]
|
||||
if raw:
|
||||
exclude.append("telegram.ext*")
|
||||
|
||||
packs = find_packages(exclude=exclude)
|
||||
|
||||
return packs, reqs
|
||||
|
||||
|
||||
def get_optional_requirements(raw: bool = False) -> Dict[str, List[str]]:
|
||||
"""Build the optional dependencies"""
|
||||
requirements = defaultdict(list)
|
||||
|
||||
with Path("requirements-opts.txt").open(encoding="utf-8") as reqs:
|
||||
for line in reqs:
|
||||
effective_line = line.strip()
|
||||
if not effective_line or effective_line.startswith("#"):
|
||||
continue
|
||||
dependency, names = effective_line.split("#")
|
||||
dependency = dependency.strip()
|
||||
for name in names.split(","):
|
||||
effective_name = name.strip()
|
||||
if effective_name.endswith("!ext"):
|
||||
if raw:
|
||||
continue
|
||||
effective_name = effective_name[:-4]
|
||||
requirements["ext"].append(dependency)
|
||||
requirements[effective_name].append(dependency)
|
||||
requirements["all"].append(dependency)
|
||||
|
||||
return requirements
|
||||
|
||||
|
||||
def get_setup_kwargs(raw: bool = False) -> Dict[str, Any]:
|
||||
"""Builds a dictionary of kwargs for the setup function"""
|
||||
packages, requirements = get_packages_requirements(raw=raw)
|
||||
|
||||
raw_ext = "-raw" if raw else ""
|
||||
readme = Path(f'README{"_RAW" if raw else ""}.rst')
|
||||
|
||||
version_file = Path("telegram/_version.py").read_text(encoding="utf-8")
|
||||
first_part = version_file.split("# SETUP.PY MARKER")[0]
|
||||
exec(first_part) # pylint: disable=exec-used
|
||||
|
||||
return {
|
||||
"script_name": f"setup{raw_ext}.py",
|
||||
"name": f"python-telegram-bot{raw_ext}",
|
||||
"version": locals()["__version__"],
|
||||
"author": "Leandro Toledo",
|
||||
"author_email": "devs@python-telegram-bot.org",
|
||||
"license": "LGPLv3",
|
||||
"url": "https://python-telegram-bot.org/",
|
||||
# Keywords supported by PyPI can be found at
|
||||
# https://github.com/pypa/warehouse/blob/aafc5185e57e67d43487ce4faa95913dd4573e14/
|
||||
# warehouse/templates/packaging/detail.html#L20-L58
|
||||
"project_urls": {
|
||||
"Documentation": "https://docs.python-telegram-bot.org",
|
||||
"Bug Tracker": "https://github.com/python-telegram-bot/python-telegram-bot/issues",
|
||||
"Source Code": "https://github.com/python-telegram-bot/python-telegram-bot",
|
||||
"News": "https://t.me/pythontelegrambotchannel",
|
||||
"Changelog": "https://docs.python-telegram-bot.org/en/stable/changelog.html",
|
||||
},
|
||||
"download_url": f"https://pypi.org/project/python-telegram-bot{raw_ext}/",
|
||||
"keywords": "python telegram bot api wrapper",
|
||||
"description": "We have made you a wrapper you can't refuse",
|
||||
"long_description": readme.read_text(encoding="utf-8"),
|
||||
"long_description_content_type": "text/x-rst",
|
||||
"packages": packages,
|
||||
"install_requires": requirements,
|
||||
"extras_require": get_optional_requirements(raw=raw),
|
||||
"include_package_data": True,
|
||||
"classifiers": [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
|
||||
"Operating System :: OS Independent",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: Communications :: Chat",
|
||||
"Topic :: Internet",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
],
|
||||
"python_requires": ">=3.8",
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# If we're building, build ptb-raw as well
|
||||
if set(sys.argv[1:]) in [{"bdist_wheel"}, {"sdist"}, {"sdist", "bdist_wheel"}]:
|
||||
args = ["python", "setup_raw.py"]
|
||||
args.extend(sys.argv[1:])
|
||||
subprocess.run(args, check=True, capture_output=True)
|
||||
|
||||
setup(**get_setup_kwargs(raw=False))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""The setup and build script for the python-telegram-bot-raw library."""
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
from setup import get_setup_kwargs
|
||||
|
||||
setup(**get_setup_kwargs(raw=True))
|
||||
+69
-31
@@ -20,6 +20,7 @@
|
||||
|
||||
__author__ = "devs@python-telegram-bot.org"
|
||||
__all__ = (
|
||||
"AffiliateInfo",
|
||||
"Animation",
|
||||
"Audio",
|
||||
"BackgroundFill",
|
||||
@@ -81,6 +82,7 @@ __all__ = (
|
||||
"ChatShared",
|
||||
"ChosenInlineResult",
|
||||
"Contact",
|
||||
"CopyTextButton",
|
||||
"Credentials",
|
||||
"DataCredentials",
|
||||
"Dice",
|
||||
@@ -100,6 +102,8 @@ __all__ = (
|
||||
"GameHighScore",
|
||||
"GeneralForumTopicHidden",
|
||||
"GeneralForumTopicUnhidden",
|
||||
"Gift",
|
||||
"Gifts",
|
||||
"Giveaway",
|
||||
"GiveawayCompleted",
|
||||
"GiveawayCreated",
|
||||
@@ -142,6 +146,9 @@ __all__ = (
|
||||
"InputMediaPhoto",
|
||||
"InputMediaVideo",
|
||||
"InputMessageContent",
|
||||
"InputPaidMedia",
|
||||
"InputPaidMediaPhoto",
|
||||
"InputPaidMediaVideo",
|
||||
"InputPollOption",
|
||||
"InputSticker",
|
||||
"InputTextMessageContent",
|
||||
@@ -173,6 +180,12 @@ __all__ = (
|
||||
"MessageReactionCountUpdated",
|
||||
"MessageReactionUpdated",
|
||||
"OrderInfo",
|
||||
"PaidMedia",
|
||||
"PaidMediaInfo",
|
||||
"PaidMediaPhoto",
|
||||
"PaidMediaPreview",
|
||||
"PaidMediaPurchased",
|
||||
"PaidMediaVideo",
|
||||
"PassportData",
|
||||
"PassportElementError",
|
||||
"PassportElementErrorDataField",
|
||||
@@ -191,15 +204,22 @@ __all__ = (
|
||||
"PollAnswer",
|
||||
"PollOption",
|
||||
"PreCheckoutQuery",
|
||||
"PreparedInlineMessage",
|
||||
"ProximityAlertTriggered",
|
||||
"ReactionCount",
|
||||
"ReactionType",
|
||||
"ReactionTypeCustomEmoji",
|
||||
"ReactionTypeEmoji",
|
||||
"ReactionTypePaid",
|
||||
"RefundedPayment",
|
||||
"ReplyKeyboardMarkup",
|
||||
"ReplyKeyboardRemove",
|
||||
"ReplyParameters",
|
||||
"ResidentialAddress",
|
||||
"RevenueWithdrawalState",
|
||||
"RevenueWithdrawalStateFailed",
|
||||
"RevenueWithdrawalStatePending",
|
||||
"RevenueWithdrawalStateSucceeded",
|
||||
"SecureData",
|
||||
"SecureValue",
|
||||
"SentWebAppMessage",
|
||||
@@ -207,6 +227,8 @@ __all__ = (
|
||||
"ShippingAddress",
|
||||
"ShippingOption",
|
||||
"ShippingQuery",
|
||||
"StarTransaction",
|
||||
"StarTransactions",
|
||||
"Sticker",
|
||||
"StickerSet",
|
||||
"Story",
|
||||
@@ -214,6 +236,13 @@ __all__ = (
|
||||
"SwitchInlineQueryChosenChat",
|
||||
"TelegramObject",
|
||||
"TextQuote",
|
||||
"TransactionPartner",
|
||||
"TransactionPartnerAffiliateProgram",
|
||||
"TransactionPartnerFragment",
|
||||
"TransactionPartnerOther",
|
||||
"TransactionPartnerTelegramAds",
|
||||
"TransactionPartnerTelegramApi",
|
||||
"TransactionPartnerUser",
|
||||
"Update",
|
||||
"User",
|
||||
"UserChatBoosts",
|
||||
@@ -242,8 +271,6 @@ __all__ = (
|
||||
"warnings",
|
||||
)
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from . import _version, constants, error, helpers, request, warnings
|
||||
from ._birthdate import Birthdate
|
||||
from ._bot import Bot
|
||||
@@ -310,6 +337,7 @@ from ._chatmember import (
|
||||
from ._chatmemberupdated import ChatMemberUpdated
|
||||
from ._chatpermissions import ChatPermissions
|
||||
from ._choseninlineresult import ChosenInlineResult
|
||||
from ._copytextbutton import CopyTextButton
|
||||
from ._dice import Dice
|
||||
from ._files.animation import Animation
|
||||
from ._files.audio import Audio
|
||||
@@ -325,6 +353,9 @@ from ._files.inputmedia import (
|
||||
InputMediaDocument,
|
||||
InputMediaPhoto,
|
||||
InputMediaVideo,
|
||||
InputPaidMedia,
|
||||
InputPaidMediaPhoto,
|
||||
InputPaidMediaVideo,
|
||||
)
|
||||
from ._files.inputsticker import InputSticker
|
||||
from ._files.location import Location
|
||||
@@ -347,6 +378,7 @@ from ._forumtopic import (
|
||||
from ._games.callbackgame import CallbackGame
|
||||
from ._games.game import Game
|
||||
from ._games.gamehighscore import GameHighScore
|
||||
from ._gifts import Gift, Gifts
|
||||
from ._giveaway import Giveaway, GiveawayCompleted, GiveawayCreated, GiveawayWinners
|
||||
from ._inline.inlinekeyboardbutton import InlineKeyboardButton
|
||||
from ._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
@@ -379,6 +411,7 @@ from ._inline.inputlocationmessagecontent import InputLocationMessageContent
|
||||
from ._inline.inputmessagecontent import InputMessageContent
|
||||
from ._inline.inputtextmessagecontent import InputTextMessageContent
|
||||
from ._inline.inputvenuemessagecontent import InputVenueMessageContent
|
||||
from ._inline.preparedinlinemessage import PreparedInlineMessage
|
||||
from ._keyboardbutton import KeyboardButton
|
||||
from ._keyboardbuttonpolltype import KeyboardButtonPollType
|
||||
from ._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers
|
||||
@@ -397,6 +430,14 @@ from ._messageorigin import (
|
||||
MessageOriginUser,
|
||||
)
|
||||
from ._messagereactionupdated import MessageReactionCountUpdated, MessageReactionUpdated
|
||||
from ._paidmedia import (
|
||||
PaidMedia,
|
||||
PaidMediaInfo,
|
||||
PaidMediaPhoto,
|
||||
PaidMediaPreview,
|
||||
PaidMediaPurchased,
|
||||
PaidMediaVideo,
|
||||
)
|
||||
from ._passport.credentials import (
|
||||
Credentials,
|
||||
DataCredentials,
|
||||
@@ -425,13 +466,36 @@ from ._payment.invoice import Invoice
|
||||
from ._payment.labeledprice import LabeledPrice
|
||||
from ._payment.orderinfo import OrderInfo
|
||||
from ._payment.precheckoutquery import PreCheckoutQuery
|
||||
from ._payment.refundedpayment import RefundedPayment
|
||||
from ._payment.shippingaddress import ShippingAddress
|
||||
from ._payment.shippingoption import ShippingOption
|
||||
from ._payment.shippingquery import ShippingQuery
|
||||
from ._payment.stars import (
|
||||
AffiliateInfo,
|
||||
RevenueWithdrawalState,
|
||||
RevenueWithdrawalStateFailed,
|
||||
RevenueWithdrawalStatePending,
|
||||
RevenueWithdrawalStateSucceeded,
|
||||
StarTransaction,
|
||||
StarTransactions,
|
||||
TransactionPartner,
|
||||
TransactionPartnerAffiliateProgram,
|
||||
TransactionPartnerFragment,
|
||||
TransactionPartnerOther,
|
||||
TransactionPartnerTelegramAds,
|
||||
TransactionPartnerTelegramApi,
|
||||
TransactionPartnerUser,
|
||||
)
|
||||
from ._payment.successfulpayment import SuccessfulPayment
|
||||
from ._poll import InputPollOption, Poll, PollAnswer, PollOption
|
||||
from ._proximityalerttriggered import ProximityAlertTriggered
|
||||
from ._reaction import ReactionCount, ReactionType, ReactionTypeCustomEmoji, ReactionTypeEmoji
|
||||
from ._reaction import (
|
||||
ReactionCount,
|
||||
ReactionType,
|
||||
ReactionTypeCustomEmoji,
|
||||
ReactionTypeEmoji,
|
||||
ReactionTypePaid,
|
||||
)
|
||||
from ._reply import ExternalReplyInfo, ReplyParameters, TextQuote
|
||||
from ._replykeyboardmarkup import ReplyKeyboardMarkup
|
||||
from ._replykeyboardremove import ReplyKeyboardRemove
|
||||
@@ -443,7 +507,6 @@ from ._telegramobject import TelegramObject
|
||||
from ._update import Update
|
||||
from ._user import User
|
||||
from ._userprofilephotos import UserProfilePhotos
|
||||
from ._utils.warnings import warn
|
||||
from ._videochat import (
|
||||
VideoChatEnded,
|
||||
VideoChatParticipantsInvited,
|
||||
@@ -472,33 +535,8 @@ __version_info__: _version.Version = _version.__version_info__
|
||||
#:
|
||||
#: .. versionchanged:: 20.0
|
||||
#: This constant was previously named ``bot_api_version``.
|
||||
__bot_api_version__: str = _version.__bot_api_version__
|
||||
__bot_api_version__: str = constants.BOT_API_VERSION
|
||||
#: :class:`typing.NamedTuple`: Shortcut for :const:`telegram.constants.BOT_API_VERSION_INFO`.
|
||||
#:
|
||||
#: .. versionadded:: 20.0
|
||||
__bot_api_version_info__: constants._BotAPIVersion = _version.__bot_api_version_info__
|
||||
|
||||
|
||||
if not (Path(__file__).parent.resolve().absolute() / "ext").exists():
|
||||
_MESSAGE = (
|
||||
"Hey. You seem to be using the `python-telegram-bot-raw` library. "
|
||||
"Please note that this libray has been deprecated and will no longer be updated. "
|
||||
"Please instead use the `python-telegram-bot` library. The change requires no "
|
||||
"changes in your code and requires no additional dependencies. For additional "
|
||||
"information, please see the channel post at "
|
||||
"https://t.me/pythontelegrambotchannel/145."
|
||||
)
|
||||
|
||||
# DeprecationWarning is ignored by default in Python 3.7 and later by default outside
|
||||
# __main__ modules. We use both warning categories to increase the chance of the user
|
||||
# seeing the warning.
|
||||
|
||||
warn(
|
||||
warnings.PTBDeprecationWarning(version="21.3", message=_MESSAGE),
|
||||
stacklevel=2,
|
||||
)
|
||||
warn(
|
||||
message=_MESSAGE,
|
||||
category=warnings.PTBUserWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
__bot_api_version_info__: constants._BotAPIVersion = constants.BOT_API_VERSION_INFO
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
# pylint: disable=missing-module-docstring
|
||||
# ruff: noqa: T201, D100, S603, S607
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
+853
-165
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
# pylint: disable=redefined-builtin
|
||||
"""This module contains objects representing Telegram bot command scopes."""
|
||||
from typing import TYPE_CHECKING, Dict, Final, Optional, Type, Union
|
||||
from typing import TYPE_CHECKING, Final, Optional, Union
|
||||
|
||||
from telegram import constants
|
||||
from telegram._telegramobject import TelegramObject
|
||||
@@ -84,13 +84,19 @@ class BotCommandScope(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BotCommandScope"]:
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BotCommandScope"]:
|
||||
"""Converts JSON data to the appropriate :class:`BotCommandScope` object, i.e. takes
|
||||
care of selecting the correct subclass.
|
||||
|
||||
Args:
|
||||
data (Dict[:obj:`str`, ...]): The JSON data.
|
||||
bot (:class:`telegram.Bot`): The bot associated with this object.
|
||||
data (dict[:obj:`str`, ...]): The JSON data.
|
||||
bot (:class:`telegram.Bot`, optional): The bot associated with this object. Defaults to
|
||||
:obj:`None`, in which case shortcut methods will not be available.
|
||||
|
||||
.. versionchanged:: 21.4
|
||||
:paramref:`bot` is now optional and defaults to :obj:`None`
|
||||
|
||||
Returns:
|
||||
The Telegram object.
|
||||
@@ -101,7 +107,7 @@ class BotCommandScope(TelegramObject):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
_class_mapping: Dict[str, Type[BotCommandScope]] = {
|
||||
_class_mapping: dict[str, type[BotCommandScope]] = {
|
||||
cls.DEFAULT: BotCommandScopeDefault,
|
||||
cls.ALL_PRIVATE_CHATS: BotCommandScopeAllPrivateChats,
|
||||
cls.ALL_GROUP_CHATS: BotCommandScopeAllGroupChats,
|
||||
|
||||
+26
-15
@@ -19,8 +19,9 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/]
|
||||
"""This module contains the Telegram Business related classes."""
|
||||
|
||||
from collections.abc import Sequence
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Optional, Sequence, Tuple
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._chat import Chat
|
||||
from telegram._files.location import Location
|
||||
@@ -106,7 +107,9 @@ class BusinessConnection(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessConnection"]:
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BusinessConnection"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
@@ -143,7 +146,7 @@ class BusinessMessagesDeleted(TelegramObject):
|
||||
business_connection_id (:obj:`str`): Unique identifier of the business connection.
|
||||
chat (:class:`telegram.Chat`): Information about a chat in the business account. The bot
|
||||
may not have access to the chat or the corresponding user.
|
||||
message_ids (Tuple[:obj:`int`]): A list of identifiers of the deleted messages in the
|
||||
message_ids (tuple[:obj:`int`]): A list of identifiers of the deleted messages in the
|
||||
chat of the business account.
|
||||
"""
|
||||
|
||||
@@ -164,7 +167,7 @@ class BusinessMessagesDeleted(TelegramObject):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.business_connection_id: str = business_connection_id
|
||||
self.chat: Chat = chat
|
||||
self.message_ids: Tuple[int, ...] = parse_sequence_arg(message_ids)
|
||||
self.message_ids: tuple[int, ...] = parse_sequence_arg(message_ids)
|
||||
|
||||
self._id_attrs = (
|
||||
self.business_connection_id,
|
||||
@@ -175,7 +178,9 @@ class BusinessMessagesDeleted(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessMessagesDeleted"]:
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BusinessMessagesDeleted"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
@@ -232,7 +237,9 @@ class BusinessIntro(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessIntro"]:
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BusinessIntro"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
@@ -284,7 +291,9 @@ class BusinessLocation(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessLocation"]:
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BusinessLocation"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
@@ -351,37 +360,37 @@ class BusinessOpeningHoursInterval(TelegramObject):
|
||||
self.opening_minute: int = opening_minute
|
||||
self.closing_minute: int = closing_minute
|
||||
|
||||
self._opening_time: Optional[Tuple[int, int, int]] = None
|
||||
self._closing_time: Optional[Tuple[int, int, int]] = None
|
||||
self._opening_time: Optional[tuple[int, int, int]] = None
|
||||
self._closing_time: Optional[tuple[int, int, int]] = None
|
||||
|
||||
self._id_attrs = (self.opening_minute, self.closing_minute)
|
||||
|
||||
self._freeze()
|
||||
|
||||
def _parse_minute(self, minute: int) -> Tuple[int, int, int]:
|
||||
def _parse_minute(self, minute: int) -> tuple[int, int, int]:
|
||||
return (minute // 1440, minute % 1440 // 60, minute % 1440 % 60)
|
||||
|
||||
@property
|
||||
def opening_time(self) -> Tuple[int, int, int]:
|
||||
def opening_time(self) -> tuple[int, int, int]:
|
||||
"""Convenience attribute. A :obj:`tuple` parsed from :attr:`opening_minute`. It contains
|
||||
the `weekday`, `hour` and `minute` in the same ranges as :attr:`datetime.datetime.weekday`,
|
||||
:attr:`datetime.datetime.hour` and :attr:`datetime.datetime.minute`
|
||||
|
||||
Returns:
|
||||
Tuple[:obj:`int`, :obj:`int`, :obj:`int`]:
|
||||
tuple[:obj:`int`, :obj:`int`, :obj:`int`]:
|
||||
"""
|
||||
if self._opening_time is None:
|
||||
self._opening_time = self._parse_minute(self.opening_minute)
|
||||
return self._opening_time
|
||||
|
||||
@property
|
||||
def closing_time(self) -> Tuple[int, int, int]:
|
||||
def closing_time(self) -> tuple[int, int, int]:
|
||||
"""Convenience attribute. A :obj:`tuple` parsed from :attr:`closing_minute`. It contains
|
||||
the `weekday`, `hour` and `minute` in the same ranges as :attr:`datetime.datetime.weekday`,
|
||||
:attr:`datetime.datetime.hour` and :attr:`datetime.datetime.minute`
|
||||
|
||||
Returns:
|
||||
Tuple[:obj:`int`, :obj:`int`, :obj:`int`]:
|
||||
tuple[:obj:`int`, :obj:`int`, :obj:`int`]:
|
||||
"""
|
||||
if self._closing_time is None:
|
||||
self._closing_time = self._parse_minute(self.closing_minute)
|
||||
@@ -431,7 +440,9 @@ class BusinessOpeningHours(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessOpeningHours"]:
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BusinessOpeningHours"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
# pylint: disable=redefined-builtin
|
||||
"""This module contains an object that represents a Telegram CallbackQuery"""
|
||||
from typing import TYPE_CHECKING, Final, Optional, Sequence, Tuple, Union
|
||||
from collections.abc import Sequence
|
||||
from typing import TYPE_CHECKING, Final, Optional, Union
|
||||
|
||||
from telegram import constants
|
||||
from telegram._files.location import Location
|
||||
@@ -93,7 +94,7 @@ class CallbackQuery(TelegramObject):
|
||||
with the callback button that originated the query.
|
||||
|
||||
.. versionchanged:: 20.8
|
||||
Objects maybe be of type :class:`telegram.MaybeInaccessibleMessage` since Bot API
|
||||
Objects may be of type :class:`telegram.MaybeInaccessibleMessage` since Bot API
|
||||
7.0.
|
||||
data (:obj:`str` | :obj:`object`): Optional. Data associated with the callback button.
|
||||
Be aware that the message, which originated the query, can contain no callback buttons
|
||||
@@ -148,7 +149,9 @@ class CallbackQuery(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["CallbackQuery"]:
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["CallbackQuery"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
@@ -260,6 +263,8 @@ class CallbackQuery(TelegramObject):
|
||||
entities=entities,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
# inline messages can not be sent on behalf of a bcid
|
||||
business_connection_id=None,
|
||||
)
|
||||
return await self._get_message().edit_text(
|
||||
text=text,
|
||||
@@ -328,6 +333,8 @@ class CallbackQuery(TelegramObject):
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
# inline messages can not be sent on behalf of a bcid
|
||||
business_connection_id=None,
|
||||
)
|
||||
return await self._get_message().edit_caption(
|
||||
caption=caption,
|
||||
@@ -388,6 +395,8 @@ class CallbackQuery(TelegramObject):
|
||||
api_kwargs=api_kwargs,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
# inline messages can not be sent on behalf of a bcid
|
||||
business_connection_id=None,
|
||||
)
|
||||
return await self._get_message().edit_reply_markup(
|
||||
reply_markup=reply_markup,
|
||||
@@ -445,6 +454,8 @@ class CallbackQuery(TelegramObject):
|
||||
api_kwargs=api_kwargs,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
# inline messages can not be sent on behalf of a bcid
|
||||
business_connection_id=None,
|
||||
)
|
||||
return await self._get_message().edit_media(
|
||||
media=media,
|
||||
@@ -516,6 +527,8 @@ class CallbackQuery(TelegramObject):
|
||||
live_period=live_period,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
# inline messages can not be sent on behalf of a bcid
|
||||
business_connection_id=None,
|
||||
)
|
||||
return await self._get_message().edit_live_location(
|
||||
latitude=latitude,
|
||||
@@ -579,6 +592,8 @@ class CallbackQuery(TelegramObject):
|
||||
api_kwargs=api_kwargs,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
# inline messages can not be sent on behalf of a bcid
|
||||
business_connection_id=None,
|
||||
)
|
||||
return await self._get_message().stop_live_location(
|
||||
reply_markup=reply_markup,
|
||||
@@ -662,7 +677,7 @@ class CallbackQuery(TelegramObject):
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> Tuple["GameHighScore", ...]:
|
||||
) -> tuple["GameHighScore", ...]:
|
||||
"""Shortcut for either::
|
||||
|
||||
await update.callback_query.message.get_game_high_score(*args, **kwargs)
|
||||
@@ -681,7 +696,7 @@ class CallbackQuery(TelegramObject):
|
||||
Raises :exc:`TypeError` if :attr:`message` is not accessible.
|
||||
|
||||
Returns:
|
||||
Tuple[:class:`telegram.GameHighScore`]
|
||||
tuple[:class:`telegram.GameHighScore`]
|
||||
|
||||
Raises:
|
||||
:exc:`TypeError` if :attr:`message` is not accessible.
|
||||
@@ -819,6 +834,7 @@ class CallbackQuery(TelegramObject):
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
@@ -866,6 +882,7 @@ class CallbackQuery(TelegramObject):
|
||||
message_thread_id=message_thread_id,
|
||||
reply_parameters=reply_parameters,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
MAX_ANSWER_TEXT_LENGTH: Final[int] = (
|
||||
|
||||
+233
-13
@@ -18,9 +18,10 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Chat."""
|
||||
from collections.abc import Sequence
|
||||
from datetime import datetime
|
||||
from html import escape
|
||||
from typing import TYPE_CHECKING, Final, Optional, Sequence, Tuple, Union
|
||||
from typing import TYPE_CHECKING, Final, Optional, Union
|
||||
|
||||
from telegram import constants
|
||||
from telegram._chatpermissions import ChatPermissions
|
||||
@@ -43,11 +44,13 @@ if TYPE_CHECKING:
|
||||
ChatMember,
|
||||
Contact,
|
||||
Document,
|
||||
Gift,
|
||||
InlineKeyboardMarkup,
|
||||
InputMediaAudio,
|
||||
InputMediaDocument,
|
||||
InputMediaPhoto,
|
||||
InputMediaVideo,
|
||||
InputPaidMedia,
|
||||
InputPollOption,
|
||||
LabeledPrice,
|
||||
LinkPreviewOptions,
|
||||
@@ -295,7 +298,7 @@ class _ChatBase(TelegramObject):
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> Tuple["ChatMember", ...]:
|
||||
) -> tuple["ChatMember", ...]:
|
||||
"""Shortcut for::
|
||||
|
||||
await bot.get_chat_administrators(update.effective_chat.id, *args, **kwargs)
|
||||
@@ -304,7 +307,7 @@ class _ChatBase(TelegramObject):
|
||||
:meth:`telegram.Bot.get_chat_administrators`.
|
||||
|
||||
Returns:
|
||||
Tuple[:class:`telegram.ChatMember`]: A tuple of administrators in a chat. An Array of
|
||||
tuple[:class:`telegram.ChatMember`]: A tuple of administrators in a chat. An Array of
|
||||
:class:`telegram.ChatMember` objects that contains information about all
|
||||
chat administrators except other bots. If the chat is a group or a supergroup
|
||||
and no administrators were appointed, only the creator will be returned.
|
||||
@@ -904,6 +907,7 @@ class _ChatBase(TelegramObject):
|
||||
self,
|
||||
message_id: int,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -931,11 +935,13 @@ class _ChatBase(TelegramObject):
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def unpin_message(
|
||||
self,
|
||||
message_id: Optional[int] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -962,6 +968,7 @@ class _ChatBase(TelegramObject):
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
message_id=message_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def unpin_all_messages(
|
||||
@@ -1006,6 +1013,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1047,6 +1055,7 @@ class _ChatBase(TelegramObject):
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def delete_message(
|
||||
@@ -1124,6 +1133,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1135,7 +1145,7 @@ class _ChatBase(TelegramObject):
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
) -> Tuple["Message", ...]:
|
||||
) -> tuple["Message", ...]:
|
||||
"""Shortcut for::
|
||||
|
||||
await bot.send_media_group(update.effective_chat.id, *args, **kwargs)
|
||||
@@ -1143,7 +1153,7 @@ class _ChatBase(TelegramObject):
|
||||
For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`.
|
||||
|
||||
Returns:
|
||||
Tuple[:class:`telegram.Message`]: On success, a tuple of :class:`~telegram.Message`
|
||||
tuple[:class:`telegram.Message`]: On success, a tuple of :class:`~telegram.Message`
|
||||
instances that were sent is returned.
|
||||
|
||||
"""
|
||||
@@ -1166,6 +1176,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters=reply_parameters,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_chat_action(
|
||||
@@ -1219,6 +1230,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
@@ -1262,6 +1274,7 @@ class _ChatBase(TelegramObject):
|
||||
has_spoiler=has_spoiler,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
@@ -1278,6 +1291,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1319,6 +1333,7 @@ class _ChatBase(TelegramObject):
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_audio(
|
||||
@@ -1338,6 +1353,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1383,6 +1399,7 @@ class _ChatBase(TelegramObject):
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_document(
|
||||
@@ -1400,6 +1417,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1443,6 +1461,7 @@ class _ChatBase(TelegramObject):
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_dice(
|
||||
@@ -1455,6 +1474,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1491,6 +1511,7 @@ class _ChatBase(TelegramObject):
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_game(
|
||||
@@ -1503,6 +1524,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1539,6 +1561,7 @@ class _ChatBase(TelegramObject):
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_invoice(
|
||||
@@ -1570,6 +1593,7 @@ class _ChatBase(TelegramObject):
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1635,6 +1659,7 @@ class _ChatBase(TelegramObject):
|
||||
message_thread_id=message_thread_id,
|
||||
reply_parameters=reply_parameters,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_location(
|
||||
@@ -1652,6 +1677,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1695,6 +1721,7 @@ class _ChatBase(TelegramObject):
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_animation(
|
||||
@@ -1715,6 +1742,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
@@ -1762,6 +1790,7 @@ class _ChatBase(TelegramObject):
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
@@ -1776,6 +1805,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1813,6 +1843,7 @@ class _ChatBase(TelegramObject):
|
||||
emoji=emoji,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_venue(
|
||||
@@ -1832,6 +1863,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1877,6 +1909,7 @@ class _ChatBase(TelegramObject):
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_video(
|
||||
@@ -1898,6 +1931,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
@@ -1946,6 +1980,7 @@ class _ChatBase(TelegramObject):
|
||||
has_spoiler=has_spoiler,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
@@ -1962,6 +1997,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2003,6 +2039,7 @@ class _ChatBase(TelegramObject):
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_voice(
|
||||
@@ -2019,6 +2056,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2061,6 +2099,7 @@ class _ChatBase(TelegramObject):
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_poll(
|
||||
@@ -2086,6 +2125,7 @@ class _ChatBase(TelegramObject):
|
||||
question_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
question_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2123,6 +2163,7 @@ class _ChatBase(TelegramObject):
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
message_effect_id=message_effect_id,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
explanation=explanation,
|
||||
explanation_parse_mode=explanation_parse_mode,
|
||||
open_period=open_period,
|
||||
@@ -2150,6 +2191,7 @@ class _ChatBase(TelegramObject):
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2191,6 +2233,7 @@ class _ChatBase(TelegramObject):
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def copy_message(
|
||||
@@ -2206,6 +2249,7 @@ class _ChatBase(TelegramObject):
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2247,6 +2291,7 @@ class _ChatBase(TelegramObject):
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_copies(
|
||||
@@ -2263,7 +2308,7 @@ class _ChatBase(TelegramObject):
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> Tuple["MessageId", ...]:
|
||||
) -> tuple["MessageId", ...]:
|
||||
"""Shortcut for::
|
||||
|
||||
await bot.copy_messages(chat_id=update.effective_chat.id, *args, **kwargs)
|
||||
@@ -2275,7 +2320,7 @@ class _ChatBase(TelegramObject):
|
||||
.. versionadded:: 20.8
|
||||
|
||||
Returns:
|
||||
Tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
|
||||
tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
|
||||
of the sent messages is returned.
|
||||
|
||||
"""
|
||||
@@ -2308,7 +2353,7 @@ class _ChatBase(TelegramObject):
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> Tuple["MessageId", ...]:
|
||||
) -> tuple["MessageId", ...]:
|
||||
"""Shortcut for::
|
||||
|
||||
await bot.copy_messages(from_chat_id=update.effective_chat.id, *args, **kwargs)
|
||||
@@ -2320,7 +2365,7 @@ class _ChatBase(TelegramObject):
|
||||
.. versionadded:: 20.8
|
||||
|
||||
Returns:
|
||||
Tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
|
||||
tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
|
||||
of the sent messages is returned.
|
||||
|
||||
"""
|
||||
@@ -2437,7 +2482,7 @@ class _ChatBase(TelegramObject):
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> Tuple["MessageId", ...]:
|
||||
) -> tuple["MessageId", ...]:
|
||||
"""Shortcut for::
|
||||
|
||||
await bot.forward_messages(chat_id=update.effective_chat.id, *args, **kwargs)
|
||||
@@ -2449,7 +2494,7 @@ class _ChatBase(TelegramObject):
|
||||
.. versionadded:: 20.8
|
||||
|
||||
Returns:
|
||||
Tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
|
||||
tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
|
||||
of sent messages is returned.
|
||||
|
||||
"""
|
||||
@@ -2480,7 +2525,7 @@ class _ChatBase(TelegramObject):
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> Tuple["MessageId", ...]:
|
||||
) -> tuple["MessageId", ...]:
|
||||
"""Shortcut for::
|
||||
|
||||
await bot.forward_messages(from_chat_id=update.effective_chat.id, *args, **kwargs)
|
||||
@@ -2492,7 +2537,7 @@ class _ChatBase(TelegramObject):
|
||||
.. versionadded:: 20.8
|
||||
|
||||
Returns:
|
||||
Tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
|
||||
tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
|
||||
of sent messages is returned.
|
||||
|
||||
"""
|
||||
@@ -2661,6 +2706,81 @@ class _ChatBase(TelegramObject):
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def create_subscription_invite_link(
|
||||
self,
|
||||
subscription_period: int,
|
||||
subscription_price: int,
|
||||
name: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> "ChatInviteLink":
|
||||
"""Shortcut for::
|
||||
|
||||
await bot.create_chat_subscription_invite_link(
|
||||
chat_id=update.effective_chat.id, *args, **kwargs
|
||||
)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.create_chat_subscription_invite_link`.
|
||||
|
||||
.. versionadded:: 21.5
|
||||
|
||||
Returns:
|
||||
:class:`telegram.ChatInviteLink`
|
||||
"""
|
||||
return await self.get_bot().create_chat_subscription_invite_link(
|
||||
chat_id=self.id,
|
||||
subscription_period=subscription_period,
|
||||
subscription_price=subscription_price,
|
||||
name=name,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def edit_subscription_invite_link(
|
||||
self,
|
||||
invite_link: Union[str, "ChatInviteLink"],
|
||||
name: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> "ChatInviteLink":
|
||||
"""Shortcut for::
|
||||
|
||||
await bot.edit_chat_subscription_invite_link(
|
||||
chat_id=update.effective_chat.id, *args, **kwargs
|
||||
)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.edit_chat_subscription_invite_link`.
|
||||
|
||||
.. versionadded:: 21.5
|
||||
|
||||
Returns:
|
||||
:class:`telegram.ChatInviteLink`
|
||||
|
||||
"""
|
||||
return await self.get_bot().edit_chat_subscription_invite_link(
|
||||
chat_id=self.id,
|
||||
invite_link=invite_link,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
name=name,
|
||||
)
|
||||
|
||||
async def approve_join_request(
|
||||
self,
|
||||
user_id: int,
|
||||
@@ -3257,6 +3377,106 @@ class _ChatBase(TelegramObject):
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def send_paid_media(
|
||||
self,
|
||||
star_count: int,
|
||||
media: Sequence["InputPaidMedia"],
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
payload: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> "Message":
|
||||
"""Shortcut for::
|
||||
|
||||
await bot.send_paid_media(chat_id=update.effective_chat.id, *args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.send_paid_media`.
|
||||
|
||||
.. versionadded:: 21.4
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, instance representing the message posted.
|
||||
"""
|
||||
return await self.get_bot().send_paid_media(
|
||||
chat_id=self.id,
|
||||
star_count=star_count,
|
||||
media=media,
|
||||
caption=caption,
|
||||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_parameters=reply_parameters,
|
||||
reply_markup=reply_markup,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
payload=payload,
|
||||
allow_paid_broadcast=allow_paid_broadcast,
|
||||
)
|
||||
|
||||
async def send_gift(
|
||||
self,
|
||||
gift_id: Union[str, "Gift"],
|
||||
text: Optional[str] = None,
|
||||
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
text_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
await bot.send_gift(user_id=update.effective_chat.id, *args, **kwargs )
|
||||
|
||||
For the documentation of the arguments, please see :meth:`telegram.Bot.send_gift`.
|
||||
|
||||
Caution:
|
||||
Can only work, if the chat is a private chat, see :attr:`type`.
|
||||
|
||||
.. versionadded:: 21.8
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
"""
|
||||
return await self.get_bot().send_gift(
|
||||
user_id=self.id,
|
||||
gift_id=gift_id,
|
||||
text=text,
|
||||
text_parse_mode=text_parse_mode,
|
||||
text_entities=text_entities,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
|
||||
class Chat(_ChatBase):
|
||||
"""This object represents a chat.
|
||||
|
||||
+24
-17
@@ -17,7 +17,8 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains objects related to chat backgrounds."""
|
||||
from typing import TYPE_CHECKING, Dict, Final, Optional, Sequence, Tuple, Type
|
||||
from collections.abc import Sequence
|
||||
from typing import TYPE_CHECKING, Final, Optional
|
||||
|
||||
from telegram import constants
|
||||
from telegram._files.document import Document
|
||||
@@ -78,14 +79,16 @@ class BackgroundFill(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BackgroundFill"]:
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BackgroundFill"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
_class_mapping: Dict[str, Type[BackgroundFill]] = {
|
||||
_class_mapping: dict[str, type[BackgroundFill]] = {
|
||||
cls.SOLID: BackgroundFillSolid,
|
||||
cls.GRADIENT: BackgroundFillGradient,
|
||||
cls.FREEFORM_GRADIENT: BackgroundFillFreeformGradient,
|
||||
@@ -210,7 +213,7 @@ class BackgroundFillFreeformGradient(BackgroundFill):
|
||||
super().__init__(type=self.FREEFORM_GRADIENT, api_kwargs=api_kwargs)
|
||||
|
||||
with self._unfrozen():
|
||||
self.colors: Tuple[int, ...] = parse_sequence_arg(colors)
|
||||
self.colors: tuple[int, ...] = parse_sequence_arg(colors)
|
||||
|
||||
self._id_attrs = (self.colors,)
|
||||
|
||||
@@ -267,14 +270,16 @@ class BackgroundType(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BackgroundType"]:
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BackgroundType"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
_class_mapping: Dict[str, Type[BackgroundType]] = {
|
||||
_class_mapping: dict[str, type[BackgroundType]] = {
|
||||
cls.FILL: BackgroundTypeFill,
|
||||
cls.WALLPAPER: BackgroundTypeWallpaper,
|
||||
cls.PATTERN: BackgroundTypePattern,
|
||||
@@ -303,7 +308,7 @@ class BackgroundTypeFill(BackgroundType):
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
fill (:obj:`telegram.BackgroundFill`): The background fill.
|
||||
fill (:class:`telegram.BackgroundFill`): The background fill.
|
||||
dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a
|
||||
percentage;
|
||||
0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`.
|
||||
@@ -311,7 +316,7 @@ class BackgroundTypeFill(BackgroundType):
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the background. Always
|
||||
:attr:`~telegram.BackgroundType.FILL`.
|
||||
fill (:obj:`telegram.BackgroundFill`): The background fill.
|
||||
fill (:class:`telegram.BackgroundFill`): The background fill.
|
||||
dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a
|
||||
percentage;
|
||||
0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`.
|
||||
@@ -345,7 +350,7 @@ class BackgroundTypeWallpaper(BackgroundType):
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
document (:obj:`telegram.Document`): Document with the wallpaper
|
||||
document (:class:`telegram.Document`): Document with the wallpaper
|
||||
dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a
|
||||
percentage;
|
||||
0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`.
|
||||
@@ -357,7 +362,7 @@ class BackgroundTypeWallpaper(BackgroundType):
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the background. Always
|
||||
:attr:`~telegram.BackgroundType.WALLPAPER`.
|
||||
document (:obj:`telegram.Document`): Document with the wallpaper
|
||||
document (:class:`telegram.Document`): Document with the wallpaper
|
||||
dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a
|
||||
percentage;
|
||||
0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`.
|
||||
@@ -403,8 +408,8 @@ class BackgroundTypePattern(BackgroundType):
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
document (:obj:`telegram.Document`): Document with the pattern.
|
||||
fill (:obj:`telegram.BackgroundFill`): The background fill that is combined with
|
||||
document (:class:`telegram.Document`): Document with the pattern.
|
||||
fill (:class:`telegram.BackgroundFill`): The background fill that is combined with
|
||||
the pattern.
|
||||
intensity (:obj:`int`): Intensity of the pattern when it is shown above the filled
|
||||
background;
|
||||
@@ -418,8 +423,8 @@ class BackgroundTypePattern(BackgroundType):
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the background. Always
|
||||
:attr:`~telegram.BackgroundType.PATTERN`.
|
||||
document (:obj:`telegram.Document`): Document with the pattern.
|
||||
fill (:obj:`telegram.BackgroundFill`): The background fill that is combined with
|
||||
document (:class:`telegram.Document`): Document with the pattern.
|
||||
fill (:class:`telegram.BackgroundFill`): The background fill that is combined with
|
||||
the pattern.
|
||||
intensity (:obj:`int`): Intensity of the pattern when it is shown above the filled
|
||||
background;
|
||||
@@ -507,10 +512,10 @@ class ChatBackground(TelegramObject):
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
type (:obj:`telegram.BackgroundType`): Type of the background.
|
||||
type (:class:`telegram.BackgroundType`): Type of the background.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`telegram.BackgroundType`): Type of the background.
|
||||
type (:class:`telegram.BackgroundType`): Type of the background.
|
||||
"""
|
||||
|
||||
__slots__ = ("type",)
|
||||
@@ -528,7 +533,9 @@ class ChatBackground(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatBackground"]:
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatBackground"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user