mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-19 15:45:13 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9323caf2b8 | |||
| 77c25931a9 | |||
| b75948ede4 | |||
| b0d22acedb | |||
| 35a48f82f4 | |||
| 5d73132838 | |||
| 7c23087d08 | |||
| 2d5f4a68bb | |||
| f9f1533c40 | |||
| dfb0ae3747 | |||
| 64006aa7ae | |||
| 69ddc47a6e | |||
| a2150b3751 | |||
| 79acc1ae53 | |||
| 4cdb1a0cf7 | |||
| 6319f4bae1 | |||
| d7e063dbad | |||
| 5dd7b8f1e2 | |||
| 61b87ba318 | |||
| dd592cdd7c | |||
| f57dd52100 | |||
| 16605c54d7 | |||
| e4b0f8cb64 | |||
| f2dc0175cd | |||
| a781a4fddb | |||
| 679d038979 | |||
| d0a6e5141c | |||
| 5f35304e63 | |||
| 3fc50c78eb | |||
| 3c9bba63eb | |||
| a9a7b07b10 | |||
| e1e7b621f1 | |||
| dfb3c13d1d | |||
| f7a3f67a9f | |||
| a6cd9c5292 | |||
| df20e49db1 | |||
| 4f255b6e21 | |||
| 4afe174b5c | |||
| 2ac52018c2 | |||
| ca7a30963d | |||
| c42a230b96 | |||
| ce9742a602 | |||
| 43279543a3 | |||
| eda2172617 | |||
| 89dfa37dbf | |||
| 3709c2fa93 | |||
| da93fe94ae |
@@ -5,6 +5,9 @@ updates:
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "friday"
|
||||
labels:
|
||||
- "⚙️ dependencies"
|
||||
- "🔗 python"
|
||||
|
||||
# Updates the dependencies of the GitHub Actions workflows
|
||||
- package-ecosystem: "github-actions"
|
||||
@@ -12,3 +15,6 @@ updates:
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
day: "friday"
|
||||
labels:
|
||||
- "⚙️ dependencies"
|
||||
- "🔗 github-actions"
|
||||
|
||||
@@ -4,6 +4,8 @@ on:
|
||||
pull_request:
|
||||
types: [opened, reopened]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
process-dependabot-prs:
|
||||
permissions:
|
||||
@@ -16,14 +18,15 @@ jobs:
|
||||
|
||||
- name: Fetch Dependabot metadata
|
||||
id: dependabot-metadata
|
||||
uses: dependabot/fetch-metadata@v2.2.0
|
||||
uses: dependabot/fetch-metadata@d7267f607e9d3fb96fc2fbe83e0af444713e90b7 # v2.3.0
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Update Version Number in Other Files
|
||||
uses: jacobtomlinson/gha-find-replace@v3
|
||||
uses: jacobtomlinson/gha-find-replace@f1069b438f125e5395d84d1c6fd3b559a7880cb5 # v3
|
||||
with:
|
||||
find: ${{ steps.dependabot-metadata.outputs.previous-version }}
|
||||
replace: ${{ steps.dependabot-metadata.outputs.new-version }}
|
||||
@@ -31,7 +34,7 @@ jobs:
|
||||
exclude: CHANGES.rst
|
||||
|
||||
- name: Commit & Push Changes to PR
|
||||
uses: EndBug/add-and-commit@v9.1.4
|
||||
uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9.1.4
|
||||
with:
|
||||
message: 'Update version number in other files'
|
||||
committer_name: GitHub Actions
|
||||
|
||||
@@ -7,6 +7,8 @@ on:
|
||||
paths:
|
||||
- .github/workflows/docs-linkcheck.yml
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
test-sphinx-build:
|
||||
name: test-sphinx-linkcheck
|
||||
@@ -17,9 +19,11 @@ jobs:
|
||||
os: [ubuntu-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
@@ -28,3 +32,10 @@ jobs:
|
||||
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
|
||||
- name: Upload linkcheck output
|
||||
# Run also if the previous steps failed
|
||||
if: always()
|
||||
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||
with:
|
||||
name: linkcheck-output
|
||||
path: docs/build/html/output.*
|
||||
|
||||
@@ -8,19 +8,26 @@ on:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
test-sphinx-build:
|
||||
name: test-sphinx-build
|
||||
runs-on: ${{matrix.os}}
|
||||
permissions:
|
||||
# for uploading artifacts
|
||||
actions: write
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.10']
|
||||
os: [ubuntu-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: 'pip'
|
||||
@@ -34,7 +41,7 @@ jobs:
|
||||
- name: Build docs
|
||||
run: sphinx-build docs/source docs/build/html -W --keep-going -j auto
|
||||
- name: Upload docs
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||
with:
|
||||
name: HTML Docs
|
||||
retention-days: 7
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
name: GitHub Actions Security Analysis
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
zizmor:
|
||||
name: Security Analysis with zizmor
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@4db96194c378173c656ce18a155ffc14a9fc4355 # v5.2.2
|
||||
- name: Run zizmor
|
||||
run: uvx zizmor --persona=pedantic --format sarif . > results.sarif
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
category: zizmor
|
||||
@@ -4,6 +4,8 @@ on:
|
||||
pull_request:
|
||||
types: [opened]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
pre-commit-ci:
|
||||
permissions:
|
||||
@@ -11,7 +13,7 @@ jobs:
|
||||
pull-requests: write # for srvaroa/labeler to add labels in PR
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: srvaroa/labeler@v1.11.1
|
||||
- uses: srvaroa/labeler@fe4b1c73bb8abf2f14a44a6912a8b4fee835d631 # v1.12.0
|
||||
# Config file at .github/labeler.yml
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
@@ -4,11 +4,17 @@ on:
|
||||
schedule:
|
||||
- cron: '8 4 * * *'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# For locking the threads
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v5.0.1
|
||||
- uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
issue-inactive-days: '7'
|
||||
|
||||
@@ -4,17 +4,24 @@ on:
|
||||
# manually trigger the workflow
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Distribution
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
TAG: ${{ steps.get_tag.outputs.TAG }}
|
||||
permissions:
|
||||
# for uploading artifacts
|
||||
actions: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Install pypa/build
|
||||
@@ -23,7 +30,7 @@ jobs:
|
||||
- name: Build a binary wheel and a source tarball
|
||||
run: python3 -m build
|
||||
- name: Store the distribution packages
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
@@ -44,15 +51,16 @@ jobs:
|
||||
url: https://pypi.org/p/python-telegram-bot
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: mandatory for trusted publishing
|
||||
actions: read # for downloading artifacts
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
- name: Publish to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3
|
||||
|
||||
compute-signatures:
|
||||
name: Compute SHA1 Sums and Sign with Sigstore
|
||||
@@ -62,10 +70,11 @@ jobs:
|
||||
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: mandatory for sigstore
|
||||
actions: write # for up/downloading artifacts
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
@@ -77,13 +86,13 @@ jobs:
|
||||
sha1sum $file > $file.sha1
|
||||
done
|
||||
- name: Sign the dists with Sigstore
|
||||
uses: sigstore/gh-action-sigstore-python@v3.0.0
|
||||
uses: sigstore/gh-action-sigstore-python@f514d46b907ebcd5bedc05145c03b69c1edd8b46 # v3.0.0
|
||||
with:
|
||||
inputs: >-
|
||||
./dist/*.tar.gz
|
||||
./dist/*.whl
|
||||
- name: Store the distribution packages and signatures
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||
with:
|
||||
name: python-package-distributions-and-signatures
|
||||
path: dist/
|
||||
@@ -98,10 +107,11 @@ jobs:
|
||||
|
||||
permissions:
|
||||
contents: write # IMPORTANT: mandatory for making GitHub Releases
|
||||
actions: read # for downloading artifacts
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: python-package-distributions-and-signatures
|
||||
path: dist/
|
||||
@@ -113,7 +123,7 @@ jobs:
|
||||
# we don't define it through this workflow.
|
||||
run: >-
|
||||
gh release create
|
||||
'${{ env.TAG }}'
|
||||
"$TAG"
|
||||
--repo '${{ github.repository }}'
|
||||
--generate-notes
|
||||
- name: Upload artifact signatures to GitHub Release
|
||||
@@ -125,5 +135,5 @@ jobs:
|
||||
# sigstore-produced signatures and certificates.
|
||||
run: >-
|
||||
gh release upload
|
||||
'${{ env.TAG }}' dist/**
|
||||
"$TAG" dist/**
|
||||
--repo '${{ github.repository }}'
|
||||
|
||||
@@ -4,17 +4,24 @@ on:
|
||||
# manually trigger the workflow
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Distribution
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
TAG: ${{ steps.get_tag.outputs.TAG }}
|
||||
permissions:
|
||||
# for uploading artifacts
|
||||
actions: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Install pypa/build
|
||||
@@ -23,7 +30,7 @@ jobs:
|
||||
- name: Build a binary wheel and a source tarball
|
||||
run: python3 -m build
|
||||
- name: Store the distribution packages
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
@@ -44,15 +51,16 @@ jobs:
|
||||
url: https://test.pypi.org/p/python-telegram-bot
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: mandatory for trusted publishing
|
||||
actions: read # for downloading artifacts
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
- name: Publish to Test PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
|
||||
@@ -64,10 +72,11 @@ jobs:
|
||||
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: mandatory for sigstore
|
||||
actions: write # for up/downloading artifacts
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
@@ -79,13 +88,13 @@ jobs:
|
||||
sha1sum $file > $file.sha1
|
||||
done
|
||||
- name: Sign the dists with Sigstore
|
||||
uses: sigstore/gh-action-sigstore-python@v3.0.0
|
||||
uses: sigstore/gh-action-sigstore-python@f514d46b907ebcd5bedc05145c03b69c1edd8b46 # v3.0.0
|
||||
with:
|
||||
inputs: >-
|
||||
./dist/*.tar.gz
|
||||
./dist/*.whl
|
||||
- name: Store the distribution packages and signatures
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||
with:
|
||||
name: python-package-distributions-and-signatures
|
||||
path: dist/
|
||||
@@ -100,10 +109,11 @@ jobs:
|
||||
|
||||
permissions:
|
||||
contents: write # IMPORTANT: mandatory for making GitHub Releases
|
||||
actions: read # for downloading artifacts
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: python-package-distributions-and-signatures
|
||||
path: dist/
|
||||
@@ -115,7 +125,7 @@ jobs:
|
||||
# we don't define it through this workflow.
|
||||
run: >-
|
||||
gh release create
|
||||
'${{ env.TAG }}'
|
||||
"$TAG"
|
||||
--repo '${{ github.repository }}'
|
||||
--generate-notes
|
||||
--draft
|
||||
@@ -128,5 +138,5 @@ jobs:
|
||||
# sigstore-produced signatures and certificates.
|
||||
run: >-
|
||||
gh release upload
|
||||
'${{ env.TAG }}' dist/**
|
||||
"$TAG" dist/**
|
||||
--repo '${{ github.repository }}'
|
||||
|
||||
@@ -3,11 +3,16 @@ on:
|
||||
schedule:
|
||||
- cron: '42 2 * * *'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# For adding labels and closing
|
||||
issues: write
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0
|
||||
with:
|
||||
# PRs never get stale
|
||||
days-before-stale: 3
|
||||
|
||||
@@ -11,6 +11,8 @@ on:
|
||||
# Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions
|
||||
- cron: '7 3 * * 1,5'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
check-conformity:
|
||||
name: check-conformity
|
||||
@@ -21,9 +23,11 @@ jobs:
|
||||
os: [ubuntu-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
@@ -41,7 +45,7 @@ jobs:
|
||||
|
||||
- name: Test Summary
|
||||
id: test_summary
|
||||
uses: test-summary/action@v2.4
|
||||
uses: test-summary/action@31493c76ec9e7aa675f1585d3ed6f1da69269a86 # v2.4
|
||||
if: always() # always run, even if tests fail
|
||||
with:
|
||||
paths: .test_report_official.xml
|
||||
|
||||
@@ -9,12 +9,14 @@ on:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
test-type-completeness:
|
||||
name: test-type-completeness
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Bibo-Joshi/pyright-type-completeness@1.0.1
|
||||
- uses: Bibo-Joshi/pyright-type-completeness@c85a67ff3c66f51dcbb2d06bfcf4fe83a57d69cc # v1.0.1
|
||||
with:
|
||||
package-name: telegram
|
||||
python-version: 3.12
|
||||
|
||||
@@ -4,19 +4,21 @@ on:
|
||||
# Run first friday of the month at 03:17 - odd time to spread load on GitHub Actions
|
||||
- cron: '17 3 1-7 * 5'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
test-type-completeness:
|
||||
name: test-type-completeness
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Bibo-Joshi/pyright-type-completeness@1.0.1
|
||||
- uses: Bibo-Joshi/pyright-type-completeness@c85a67ff3c66f51dcbb2d06bfcf4fe83a57d69cc # v1.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
|
||||
uses: jannekem/run-python-script-action@bbfca66c612a28f3eeca0ae40e1f810265e2ea68 # v1.7
|
||||
env:
|
||||
TYPE_COMPLETENESS: ${{ steps.pyright-type-completeness.outputs.base-completeness-score }}
|
||||
with:
|
||||
|
||||
@@ -14,6 +14,8 @@ on:
|
||||
# Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions
|
||||
- cron: '7 3 * * 1,5'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
pytest:
|
||||
name: pytest
|
||||
@@ -24,9 +26,11 @@ jobs:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: 'pip'
|
||||
@@ -62,7 +66,8 @@ jobs:
|
||||
|
||||
# Test the rest
|
||||
export TEST_WITH_OPT_DEPS='true'
|
||||
pip install .[all]
|
||||
# need to manually install pytz here, because it's no longer in the optional reqs
|
||||
pip install .[all] pytz
|
||||
# `-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.
|
||||
@@ -79,7 +84,7 @@ jobs:
|
||||
|
||||
- name: Test Summary
|
||||
id: test_summary
|
||||
uses: test-summary/action@v2.4
|
||||
uses: test-summary/action@31493c76ec9e7aa675f1585d3ed6f1da69269a86 # v2.4
|
||||
if: always() # always run, even if tests fail
|
||||
with:
|
||||
paths: |
|
||||
@@ -87,14 +92,14 @@ jobs:
|
||||
.test_report_optionals_junit.xml
|
||||
|
||||
- name: Submit coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # v5.1.2
|
||||
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
|
||||
uses: codecov/test-results-action@4e79e65778be1cecd5df25e14af1eafb6df80ea9 # v1.0.2
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
files: .test_report_no_optionals_junit.xml,.test_report_optionals_junit.xml
|
||||
|
||||
@@ -67,6 +67,7 @@ docs/_build/
|
||||
# PyBuilder
|
||||
target/
|
||||
.idea/
|
||||
.run/
|
||||
|
||||
# Sublime Text 2
|
||||
*.sublime*
|
||||
|
||||
@@ -7,7 +7,7 @@ ci:
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: 'v0.5.6'
|
||||
rev: 'v0.8.6'
|
||||
hooks:
|
||||
- id: ruff
|
||||
name: ruff
|
||||
@@ -16,20 +16,20 @@ repos:
|
||||
- tornado~=6.4
|
||||
- APScheduler~=3.10.4
|
||||
- cachetools>=5.3.3,<5.5.0
|
||||
- aiolimiter~=1.1.0
|
||||
- aiolimiter~=1.1,<1.3
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 24.4.2
|
||||
rev: 24.10.0
|
||||
hooks:
|
||||
- id: black
|
||||
args:
|
||||
- --diff
|
||||
- --check
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 7.1.0
|
||||
rev: 7.1.1
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/PyCQA/pylint
|
||||
rev: v3.2.4
|
||||
rev: v3.3.3
|
||||
hooks:
|
||||
- id: pylint
|
||||
files: ^(?!(tests|docs)).*\.py$
|
||||
@@ -38,10 +38,10 @@ repos:
|
||||
- tornado~=6.4
|
||||
- APScheduler~=3.10.4
|
||||
- cachetools>=5.3.3,<5.5.0
|
||||
- aiolimiter~=1.1.0
|
||||
- aiolimiter~=1.1,<1.3
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.10.1
|
||||
rev: v1.14.1
|
||||
hooks:
|
||||
- id: mypy
|
||||
name: mypy-ptb
|
||||
@@ -54,7 +54,7 @@ repos:
|
||||
- tornado~=6.4
|
||||
- APScheduler~=3.10.4
|
||||
- cachetools>=5.3.3,<5.5.0
|
||||
- aiolimiter~=1.1.0
|
||||
- aiolimiter~=1.1,<1.3
|
||||
- . # this basically does `pip install -e .`
|
||||
- id: mypy
|
||||
name: mypy-examples
|
||||
@@ -68,7 +68,7 @@ repos:
|
||||
- cachetools>=5.3.3,<5.5.0
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.16.0
|
||||
rev: v3.19.1
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args:
|
||||
|
||||
+7
-1
@@ -31,6 +31,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `Ambro17 <https://github.com/Ambro17>`_
|
||||
- `Andrej Zhilenkov <https://github.com/Andrej730>`_
|
||||
- `Anton Tagunov <https://github.com/anton-tagunov>`_
|
||||
- `Anya Marcano <https://github.com/AnyaMarcanito>`
|
||||
- `Avanatiker <https://github.com/Avanatiker>`_
|
||||
- `Balduro <https://github.com/Balduro>`_
|
||||
- `Bibo-Joshi <https://github.com/Bibo-Joshi>`_
|
||||
@@ -58,12 +59,14 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `gamgi <https://github.com/gamgi>`_
|
||||
- `Gauthamram Ravichandran <https://github.com/GauthamramRavichandran>`_
|
||||
- `Harshil <https://github.com/harshil21>`_
|
||||
- `Henry Galue <https://github.com/henryg311>`
|
||||
- `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>`_
|
||||
- `Jeamhowards Montiel <https://github.com/Jeam-zx>`
|
||||
- `jeffffc <https://github.com/jeffffc>`_
|
||||
- `Jelle Besseling <https://github.com/pingiun>`_
|
||||
- `jh0ker <https://github.com/jh0ker>`_
|
||||
@@ -72,6 +75,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `Joscha Götzer <https://github.com/Rostgnom>`_
|
||||
- `jossalgon <https://github.com/jossalgon>`_
|
||||
- `JRoot3D <https://github.com/JRoot3D>`_
|
||||
- `Juan Cuevas <https://github.com/cuevasrja>`
|
||||
- `kenjitagawa <https://github.com/kenjitagawa>`_
|
||||
- `kennethcheo <https://github.com/kennethcheo>`_
|
||||
- `Kirill Vasin <https://github.com/vasinkd>`_
|
||||
@@ -81,11 +85,13 @@ 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>`_
|
||||
- `Michael Elovskikh <https://github.com/wronglink>`_
|
||||
- `Miguel C. R. <https://github.com/MiguelX413>`_
|
||||
- `Miguel Salomon <https://github.com/Migueldsc12>`
|
||||
- `miles <https://github.com/miles170>`_
|
||||
- `Mischa Krüger <https://github.com/Makman2>`_
|
||||
- `Mohd Yusuf <https://github.com/mohdyusuf2312>`_
|
||||
@@ -111,7 +117,7 @@ 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>`_
|
||||
- Snehashish Biswas
|
||||
- `Sahil Sharma <https://github.com/sahilsharma811>`_
|
||||
- `Sam Mosleh <https://github.com/sam-mosleh>`_
|
||||
- `Sascha <https://github.com/saschalalala>`_
|
||||
|
||||
+117
-1
@@ -4,6 +4,122 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
Version 21.11
|
||||
=============
|
||||
|
||||
*Released 2025-03-01*
|
||||
|
||||
This is the technical changelog for version 21.11. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Major Changes and New Features
|
||||
------------------------------
|
||||
|
||||
- Full Support for Bot API 8.3 (:pr:`4676` closes :issue:`4677`, :pr:`4682` by `aelkheir <https://github.com/aelkheir>`_, :pr:`4690` by `aelkheir <https://github.com/aelkheir>`_, :pr:`4691` by `aelkheir <https://github.com/aelkheir>`_)
|
||||
- Make ``provider_token`` Argument Optional (:pr:`4689`)
|
||||
- Remove Deprecated ``InlineQueryResultArticle.hide_url`` (:pr:`4640` closes :issue:`4638`)
|
||||
- Accept ``datetime.timedelta`` Input in ``Bot`` Method Parameters (:pr:`4651`)
|
||||
- Extend Customization Support for ``Bot.base_(file_)url`` (:pr:`4632` closes :issue:`3355`)
|
||||
- Support ``allow_paid_broadcast`` in ``AIORateLimiter`` (:pr:`4627` closes :issue:`4578`)
|
||||
- Add ``BaseUpdateProcessor.current_concurrent_updates`` (:pr:`4626` closes :issue:`3984`)
|
||||
|
||||
Minor Changes and Bug Fixes
|
||||
---------------------------
|
||||
|
||||
- Add Bootstrapping Logic to ``Application.run_*`` (:pr:`4673` closes :issue:`4657`)
|
||||
- Fix a Bug in ``edit_user_star_subscription`` (:pr:`4681` by `vavasik800 <https://github.com/vavasik800>`_)
|
||||
- Simplify Handling of Empty Data in ``TelegramObject.de_json`` and Friends (:pr:`4617` closes :issue:`4614`)
|
||||
|
||||
Documentation Improvements
|
||||
--------------------------
|
||||
|
||||
- Documentation Improvements (:pr:`4641`)
|
||||
- Overhaul Admonition Insertion in Documentation (:pr:`4462` closes :issue:`4414`)
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Stabilize Linkcheck Test (:pr:`4693`)
|
||||
- Bump ``pre-commit`` Hooks to Latest Versions (:pr:`4643`)
|
||||
- Refactor Tests for ``TelegramObject`` Classes with Subclasses (:pr:`4654` closes :issue:`4652`)
|
||||
- Use Fine Grained Permissions for GitHub Actions Workflows (:pr:`4668`)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- Bump ``actions/setup-python`` from 5.3.0 to 5.4.0 (:pr:`4665`)
|
||||
- Bump ``dependabot/fetch-metadata`` from 2.2.0 to 2.3.0 (:pr:`4666`)
|
||||
- Bump ``actions/stale`` from 9.0.0 to 9.1.0 (:pr:`4667`)
|
||||
- Bump ``astral-sh/setup-uv`` from 5.1.0 to 5.2.2 (:pr:`4664`)
|
||||
- Bump ``codecov/test-results-action`` from 1.0.1 to 1.0.2 (:pr:`4663`)
|
||||
|
||||
Version 21.10
|
||||
=============
|
||||
|
||||
*Released 2025-01-03*
|
||||
|
||||
This is the technical changelog for version 21.10. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Major Changes
|
||||
-------------
|
||||
|
||||
- Full Support for Bot API 8.2 (:pr:`4633`)
|
||||
- Bump ``apscheduler`` & Deprecate ``pytz`` Support (:pr:`4582`)
|
||||
|
||||
New Features
|
||||
------------
|
||||
- Add Parameter ``pattern`` to ``JobQueue.jobs()`` (:pr:`4613` closes :issue:`4544`)
|
||||
- Allow Input of Type ``Sticker`` for Several Methods (:pr:`4616` closes :issue:`4580`)
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
- Ensure Forward Compatibility of ``Gift`` and ``Gifts`` (:pr:`4634` closes :issue:`4637`)
|
||||
|
||||
|
||||
Documentation Improvements & Internal Changes
|
||||
---------------------------------------------
|
||||
|
||||
- Use Custom Labels for ``dependabot`` PRs (:pr:`4621`)
|
||||
- Remove Redundant ``pylint`` Suppressions (:pr:`4628`)
|
||||
- Update Copyright to 2025 (:pr:`4631`)
|
||||
- Refactor Module Structure and Tests for Star Payments Classes (:pr:`4615` closes :issue:`4593`)
|
||||
- Unify ``datetime`` Imports (:pr:`4605` by `cuevasrja <https://github.com/cuevasrja>`_ closes :issue:`4577`)
|
||||
- Add Static Security Analysis of GitHub Actions Workflows (:pr:`4606`)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- Bump ``astral-sh/setup-uv`` from 4.2.0 to 5.1.0 (:pr:`4625`)
|
||||
- Bump ``codecov/codecov-action`` from 5.1.1 to 5.1.2 (:pr:`4622`)
|
||||
- Bump ``actions/upload-artifact`` from 4.4.3 to 4.5.0 (:pr:`4623`)
|
||||
- Bump ``github/codeql-action`` from 3.27.9 to 3.28.0 (:pr:`4624`)
|
||||
|
||||
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*
|
||||
@@ -18,7 +134,7 @@ Major Changes
|
||||
Documentation Improvements
|
||||
--------------------------
|
||||
|
||||
- Documentation Improvements (:pr:`4565` by `Snehashish06 <https://github.com/Snehashish06>`_, :pr:`4573`)
|
||||
- Documentation Improvements (:pr:`4565` by Snehashish06, :pr:`4573`)
|
||||
|
||||
Version 21.7
|
||||
============
|
||||
|
||||
+4
-4
@@ -11,7 +11,7 @@
|
||||
:target: https://pypi.org/project/python-telegram-bot/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-8.0-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-8.3-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API version
|
||||
|
||||
@@ -81,7 +81,7 @@ After installing_ the library, be sure to check out the section on `working with
|
||||
Telegram API support
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All types and methods of the Telegram Bot API **8.0** are natively supported by this library.
|
||||
All types and methods of the Telegram Bot API **8.3** 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
|
||||
@@ -155,10 +155,10 @@ 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,<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``.
|
||||
* ``pip install "python-telegram-bot[job-queue]"`` installs the `APScheduler>=3.10.4,<3.12.0 <https://apscheduler.readthedocs.io/en/3.x/>`_ library. 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]"``.
|
||||
|
||||
|
||||
+202
-227
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -16,18 +16,55 @@
|
||||
# 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
|
||||
from collections import defaultdict
|
||||
from collections.abc import Iterator
|
||||
from typing import Any, Union
|
||||
from socket import socket
|
||||
from types import FunctionType
|
||||
from typing import Union
|
||||
|
||||
from apscheduler.job import Job as APSJob
|
||||
|
||||
import telegram
|
||||
import telegram._utils.defaultvalue
|
||||
import telegram._utils.types
|
||||
import telegram.ext
|
||||
import telegram.ext._utils.types
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
# Define the namespace for type resolution. This helps dealing with the internal imports that
|
||||
# we do in many places
|
||||
# The .copy() is important to avoid modifying the original namespace
|
||||
TG_NAMESPACE = vars(telegram).copy()
|
||||
TG_NAMESPACE.update(vars(telegram._utils.types))
|
||||
TG_NAMESPACE.update(vars(telegram._utils.defaultvalue))
|
||||
TG_NAMESPACE.update(vars(telegram.ext))
|
||||
TG_NAMESPACE.update(vars(telegram.ext._utils.types))
|
||||
TG_NAMESPACE.update(vars(telegram.ext._applicationbuilder))
|
||||
TG_NAMESPACE.update({"socket": socket, "APSJob": APSJob})
|
||||
|
||||
|
||||
def _iter_own_public_methods(cls: type) -> Iterator[tuple[str, type]]:
|
||||
class PublicMethod(typing.NamedTuple):
|
||||
name: str
|
||||
method: FunctionType
|
||||
|
||||
|
||||
def _is_inherited_method(cls: type, method_name: str) -> bool:
|
||||
"""Checks if a method is inherited from a parent class.
|
||||
Inheritance is not considered if the parent class is private.
|
||||
Recurses through all direcot or indirect parent classes.
|
||||
"""
|
||||
# The [1:] slice is used to exclude the class itself from the MRO.
|
||||
for base in cls.__mro__[1:]:
|
||||
if method_name in base.__dict__ and not base.__name__.startswith("_"):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _iter_own_public_methods(cls: type) -> Iterator[PublicMethod]:
|
||||
"""Iterates over methods of a class that are not protected/private,
|
||||
not camelCase and not inherited from the parent class.
|
||||
|
||||
@@ -35,13 +72,15 @@ def _iter_own_public_methods(cls: type) -> Iterator[tuple[str, type]]:
|
||||
|
||||
This function is defined outside the class because it is used to create class constants.
|
||||
"""
|
||||
return (
|
||||
m
|
||||
for m in inspect.getmembers(cls, predicate=inspect.isfunction) # not .ismethod
|
||||
if not m[0].startswith("_")
|
||||
and m[0].islower() # to avoid camelCase methods
|
||||
and m[0] in cls.__dict__ # method is not inherited from parent class
|
||||
)
|
||||
|
||||
# Use .isfunction() instead of .ismethod() because we want to include static methods.
|
||||
for m in inspect.getmembers(cls, predicate=inspect.isfunction):
|
||||
if (
|
||||
not m[0].startswith("_")
|
||||
and m[0].islower() # to avoid camelCase methods
|
||||
and not _is_inherited_method(cls, m[0])
|
||||
):
|
||||
yield PublicMethod(m[0], m[1])
|
||||
|
||||
|
||||
class AdmonitionInserter:
|
||||
@@ -58,18 +97,12 @@ class AdmonitionInserter:
|
||||
start and end markers.
|
||||
"""
|
||||
|
||||
FORWARD_REF_SKIP_PATTERN = re.compile(r"^ForwardRef\('DefaultValue\[\w+]'\)$")
|
||||
"""A pattern that will be used to skip known ForwardRef's that need not be resolved
|
||||
to a Telegram class, e.g.:
|
||||
ForwardRef('DefaultValue[None]')
|
||||
ForwardRef('DefaultValue[DVValueType]')
|
||||
"""
|
||||
|
||||
METHOD_NAMES_FOR_BOT_AND_APPBUILDER: typing.ClassVar[dict[type, str]] = {
|
||||
cls: tuple(m[0] for m in _iter_own_public_methods(cls)) # m[0] means we take only names
|
||||
for cls in (telegram.Bot, telegram.ext.ApplicationBuilder)
|
||||
METHOD_NAMES_FOR_BOT_APP_APPBUILDER: typing.ClassVar[dict[type, str]] = {
|
||||
cls: tuple(m.name for m in _iter_own_public_methods(cls))
|
||||
for cls in (telegram.Bot, telegram.ext.ApplicationBuilder, telegram.ext.Application)
|
||||
}
|
||||
"""A dictionary mapping Bot and ApplicationBuilder classes to their relevant methods that will
|
||||
"""A dictionary mapping Bot, Application & ApplicationBuilder classes to their relevant methods
|
||||
that will
|
||||
be mentioned in 'Returned in' and 'Use in' admonitions in other classes' docstrings.
|
||||
Methods must be public, not aliases, not inherited from TelegramObject.
|
||||
"""
|
||||
@@ -83,13 +116,20 @@ class AdmonitionInserter:
|
||||
"""Dictionary with admonitions. Contains sub-dictionaries, one per admonition type.
|
||||
Each sub-dictionary matches bot methods (for "Shortcuts") or telegram classes (for other
|
||||
admonition types) to texts of admonitions, e.g.:
|
||||
|
||||
```
|
||||
{
|
||||
"use_in": {<class 'telegram._chatinvitelink.ChatInviteLink'>:
|
||||
<"Use in" admonition for ChatInviteLink>, ...},
|
||||
"available_in": {<class 'telegram._chatinvitelink.ChatInviteLink'>:
|
||||
<"Available in" admonition">, ...},
|
||||
"returned_in": {...}
|
||||
"use_in": {
|
||||
<class 'telegram._chatinvitelink.ChatInviteLink'>:
|
||||
<"Use in" admonition for ChatInviteLink>,
|
||||
...
|
||||
},
|
||||
"available_in": {
|
||||
<class 'telegram._chatinvitelink.ChatInviteLink'>:
|
||||
<"Available in" admonition">,
|
||||
...
|
||||
},
|
||||
"returned_in": {...}
|
||||
}
|
||||
```
|
||||
"""
|
||||
@@ -128,34 +168,6 @@ class AdmonitionInserter:
|
||||
# i.e. {telegram._files.sticker.Sticker: {":attr:`telegram.Message.sticker`", ...}}
|
||||
attrs_for_class = defaultdict(set)
|
||||
|
||||
# The following regex is supposed to capture a class name in a line like this:
|
||||
# media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send.
|
||||
#
|
||||
# Note that even if such typing description spans over multiple lines but each line ends
|
||||
# with a backslash (otherwise Sphinx will throw an error)
|
||||
# (e.g. EncryptedPassportElement.data), then Sphinx will combine these lines into a single
|
||||
# line automatically, and it will contain no backslash (only some extra many whitespaces
|
||||
# from the indentation).
|
||||
|
||||
attr_docstr_pattern = re.compile(
|
||||
r"^\s*(?P<attr_name>[a-z_]+)" # Any number of spaces, named group for attribute
|
||||
r"\s?\(" # Optional whitespace, opening parenthesis
|
||||
r".*" # Any number of characters (that could denote a built-in type)
|
||||
r":(class|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.
|
||||
r".*$", # Any number of characters, end of string (end of line)
|
||||
re.VERBOSE,
|
||||
)
|
||||
|
||||
# for properties: there is no attr name in docstring. Just check if there's a class name.
|
||||
prop_docstring_pattern = re.compile(r":(class|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|obj):`~?(?P<class_name>[\w.]*)`")
|
||||
|
||||
classes_to_inspect = inspect.getmembers(telegram, inspect.isclass) + inspect.getmembers(
|
||||
telegram.ext, inspect.isclass
|
||||
)
|
||||
@@ -166,40 +178,31 @@ class AdmonitionInserter:
|
||||
# docstrings.
|
||||
name_of_inspected_class_in_docstr = self._generate_class_name_for_link(inspected_class)
|
||||
|
||||
# Parsing part of the docstring with attributes (parsing of properties follows later)
|
||||
docstring_lines = inspect.getdoc(inspected_class).splitlines()
|
||||
lines_with_attrs = []
|
||||
for idx, line in enumerate(docstring_lines):
|
||||
if line.strip() == "Attributes:":
|
||||
lines_with_attrs = docstring_lines[idx + 1 :]
|
||||
break
|
||||
# Writing to dictionary: matching the class found in the type hint
|
||||
# and its subclasses to the attribute of the class being inspected.
|
||||
# The class in the attribute typehint (or its subclass) is the key,
|
||||
# ReST link to attribute of the class currently being inspected is the value.
|
||||
|
||||
for line in lines_with_attrs:
|
||||
if not (line_match := attr_docstr_pattern.match(line)):
|
||||
continue
|
||||
|
||||
target_attr = line_match.group("attr_name")
|
||||
# a typing description of one attribute can contain multiple classes
|
||||
for match in single_class_name_pattern.finditer(line):
|
||||
name_of_class_in_attr = match.group("class_name")
|
||||
|
||||
# Writing to dictionary: matching the class found in the docstring
|
||||
# and its subclasses to the attribute of the class being inspected.
|
||||
# The class in the attribute docstring (or its subclass) is the key,
|
||||
# ReST link to attribute of the class currently being inspected is the value.
|
||||
try:
|
||||
self._resolve_arg_and_add_link(
|
||||
arg=name_of_class_in_attr,
|
||||
dict_of_methods_for_class=attrs_for_class,
|
||||
link=f":attr:`{name_of_inspected_class_in_docstr}.{target_attr}`",
|
||||
)
|
||||
except NotImplementedError as e:
|
||||
raise NotImplementedError(
|
||||
"Error generating Sphinx 'Available in' admonition "
|
||||
f"(admonition_inserter.py). Class {name_of_class_in_attr} present in "
|
||||
f"attribute {target_attr} of class {name_of_inspected_class_in_docstr}"
|
||||
f" could not be resolved. {e!s}"
|
||||
) from e
|
||||
# best effort - args of __init__ means not all attributes are covered, but there is no
|
||||
# other way to get type hints of all attributes, other than doing ast parsing maybe.
|
||||
# (Docstring parsing was discontinued with the closing of #4414)
|
||||
type_hints = typing.get_type_hints(inspected_class.__init__, localns=TG_NAMESPACE)
|
||||
class_attrs = [slot for slot in mro_slots(inspected_class) if not slot.startswith("_")]
|
||||
for target_attr in class_attrs:
|
||||
try:
|
||||
self._resolve_arg_and_add_link(
|
||||
dict_of_methods_for_class=attrs_for_class,
|
||||
link=f":attr:`{name_of_inspected_class_in_docstr}.{target_attr}`",
|
||||
type_hints={target_attr: type_hints.get(target_attr)},
|
||||
resolve_nested_type_vars=False,
|
||||
)
|
||||
except NotImplementedError as e:
|
||||
raise NotImplementedError(
|
||||
"Error generating Sphinx 'Available in' admonition "
|
||||
f"(admonition_inserter.py). Class {inspected_class} present in "
|
||||
f"attribute {target_attr} of class {name_of_inspected_class_in_docstr}"
|
||||
f" could not be resolved. {e!s}"
|
||||
) from e
|
||||
|
||||
# Properties need to be parsed separately because they act like attributes but not
|
||||
# listed as attributes.
|
||||
@@ -210,39 +213,29 @@ class AdmonitionInserter:
|
||||
if prop_name not in inspected_class.__dict__:
|
||||
continue
|
||||
|
||||
# 1. Can't use typing.get_type_hints because double-quoted type hints
|
||||
# (like "Application") will throw a NameError
|
||||
# 2. Can't use inspect.signature because return annotations of properties can be
|
||||
# hard to parse (like "(self) -> BD").
|
||||
# 3. fget is used to access the actual function under the property wrapper
|
||||
docstring = inspect.getdoc(getattr(inspected_class, prop_name).fget)
|
||||
if docstring is None:
|
||||
continue
|
||||
# fget is used to access the actual function under the property wrapper
|
||||
type_hints = typing.get_type_hints(
|
||||
getattr(inspected_class, prop_name).fget, localns=TG_NAMESPACE
|
||||
)
|
||||
|
||||
first_line = docstring.splitlines()[0]
|
||||
if not prop_docstring_pattern.match(first_line):
|
||||
continue
|
||||
|
||||
for match in single_class_name_pattern.finditer(first_line):
|
||||
name_of_class_in_prop = match.group("class_name")
|
||||
|
||||
# Writing to dictionary: matching the class found in the docstring and its
|
||||
# subclasses to the property of the class being inspected.
|
||||
# The class in the property docstring (or its subclass) is the key,
|
||||
# ReST link to property of the class currently being inspected is the value.
|
||||
try:
|
||||
self._resolve_arg_and_add_link(
|
||||
arg=name_of_class_in_prop,
|
||||
dict_of_methods_for_class=attrs_for_class,
|
||||
link=f":attr:`{name_of_inspected_class_in_docstr}.{prop_name}`",
|
||||
)
|
||||
except NotImplementedError as e:
|
||||
raise NotImplementedError(
|
||||
"Error generating Sphinx 'Available in' admonition "
|
||||
f"(admonition_inserter.py). Class {name_of_class_in_prop} present in "
|
||||
f"property {prop_name} of class {name_of_inspected_class_in_docstr}"
|
||||
f" could not be resolved. {e!s}"
|
||||
) from e
|
||||
# Writing to dictionary: matching the class found in the docstring and its
|
||||
# subclasses to the property of the class being inspected.
|
||||
# The class in the property docstring (or its subclass) is the key,
|
||||
# ReST link to property of the class currently being inspected is the value.
|
||||
try:
|
||||
self._resolve_arg_and_add_link(
|
||||
dict_of_methods_for_class=attrs_for_class,
|
||||
link=f":attr:`{name_of_inspected_class_in_docstr}.{prop_name}`",
|
||||
type_hints={prop_name: type_hints.get("return")},
|
||||
resolve_nested_type_vars=False,
|
||||
)
|
||||
except NotImplementedError as e:
|
||||
raise NotImplementedError(
|
||||
"Error generating Sphinx 'Available in' admonition "
|
||||
f"(admonition_inserter.py). Class {inspected_class} present in "
|
||||
f"property {prop_name} of class {name_of_inspected_class_in_docstr}"
|
||||
f" could not be resolved. {e!s}"
|
||||
) from e
|
||||
|
||||
return self._generate_admonitions(attrs_for_class, admonition_type="available_in")
|
||||
|
||||
@@ -250,29 +243,28 @@ class AdmonitionInserter:
|
||||
"""Creates a dictionary with 'Returned in' admonitions for classes that are returned
|
||||
in Bot's and ApplicationBuilder's methods.
|
||||
"""
|
||||
|
||||
# Generate a mapping of classes to ReST links to Bot methods which return it,
|
||||
# i.e. {<class 'telegram._message.Message'>: {:meth:`telegram.Bot.send_message`, ...}}
|
||||
methods_for_class = defaultdict(set)
|
||||
|
||||
for cls, method_names in self.METHOD_NAMES_FOR_BOT_AND_APPBUILDER.items():
|
||||
for cls, method_names in self.METHOD_NAMES_FOR_BOT_APP_APPBUILDER.items():
|
||||
for method_name in method_names:
|
||||
sig = inspect.signature(getattr(cls, method_name))
|
||||
ret_annot = sig.return_annotation
|
||||
|
||||
method_link = self._generate_link_to_method(method_name, cls)
|
||||
arg = getattr(cls, method_name)
|
||||
ret_type_hint = typing.get_type_hints(arg, localns=TG_NAMESPACE)
|
||||
|
||||
try:
|
||||
self._resolve_arg_and_add_link(
|
||||
arg=ret_annot,
|
||||
dict_of_methods_for_class=methods_for_class,
|
||||
link=method_link,
|
||||
type_hints={"return": ret_type_hint.get("return")},
|
||||
resolve_nested_type_vars=False,
|
||||
)
|
||||
except NotImplementedError as e:
|
||||
raise NotImplementedError(
|
||||
"Error generating Sphinx 'Returned in' admonition "
|
||||
f"(admonition_inserter.py). {cls}, method {method_name}. "
|
||||
f"Couldn't resolve type hint in return annotation {ret_annot}. {e!s}"
|
||||
f"Couldn't resolve type hint in return annotation {ret_type_hint}. {e!s}"
|
||||
) from e
|
||||
|
||||
return self._generate_admonitions(methods_for_class, admonition_type="returned_in")
|
||||
@@ -299,8 +291,13 @@ class AdmonitionInserter:
|
||||
# inspect methods of all telegram classes for return statements that indicate
|
||||
# that this given method is a shortcut for a Bot method
|
||||
for _class_name, cls in inspect.getmembers(telegram, predicate=inspect.isclass):
|
||||
# no need to inspect Bot's own methods, as Bot can't have shortcuts in Bot
|
||||
if not cls.__module__.startswith("telegram"):
|
||||
# For some reason inspect.getmembers() also yields some classes that are
|
||||
# imported in the namespace but not part of the telegram module.
|
||||
continue
|
||||
|
||||
if cls is telegram.Bot:
|
||||
# no need to inspect Bot's own methods, as Bot can't have shortcuts in Bot
|
||||
continue
|
||||
|
||||
for method_name, method in _iter_own_public_methods(cls):
|
||||
@@ -310,9 +307,7 @@ class AdmonitionInserter:
|
||||
continue
|
||||
|
||||
bot_method = getattr(telegram.Bot, bot_method_match.group())
|
||||
|
||||
link_to_shortcut_method = self._generate_link_to_method(method_name, cls)
|
||||
|
||||
shortcuts_for_bot_method[bot_method].add(link_to_shortcut_method)
|
||||
|
||||
return self._generate_admonitions(shortcuts_for_bot_method, admonition_type="shortcuts")
|
||||
@@ -327,26 +322,24 @@ class AdmonitionInserter:
|
||||
# {:meth:`telegram.Bot.answer_inline_query`, ...}}
|
||||
methods_for_class = defaultdict(set)
|
||||
|
||||
for cls, method_names in self.METHOD_NAMES_FOR_BOT_AND_APPBUILDER.items():
|
||||
for cls, method_names in self.METHOD_NAMES_FOR_BOT_APP_APPBUILDER.items():
|
||||
for method_name in method_names:
|
||||
method_link = self._generate_link_to_method(method_name, cls)
|
||||
|
||||
sig = inspect.signature(getattr(cls, method_name))
|
||||
parameters = sig.parameters
|
||||
|
||||
for param in parameters.values():
|
||||
try:
|
||||
self._resolve_arg_and_add_link(
|
||||
arg=param.annotation,
|
||||
dict_of_methods_for_class=methods_for_class,
|
||||
link=method_link,
|
||||
)
|
||||
except NotImplementedError as e:
|
||||
raise NotImplementedError(
|
||||
"Error generating Sphinx 'Use in' admonition "
|
||||
f"(admonition_inserter.py). {cls}, method {method_name}, parameter "
|
||||
f"{param}: Couldn't resolve type hint {param.annotation}. {e!s}"
|
||||
) from e
|
||||
arg = getattr(cls, method_name)
|
||||
param_type_hints = typing.get_type_hints(arg, localns=TG_NAMESPACE)
|
||||
param_type_hints.pop("return", None)
|
||||
try:
|
||||
self._resolve_arg_and_add_link(
|
||||
dict_of_methods_for_class=methods_for_class,
|
||||
link=method_link,
|
||||
type_hints=param_type_hints,
|
||||
)
|
||||
except NotImplementedError as e:
|
||||
raise NotImplementedError(
|
||||
"Error generating Sphinx 'Use in' admonition "
|
||||
f"(admonition_inserter.py). {cls}, method {method_name}, parameter "
|
||||
) from e
|
||||
|
||||
return self._generate_admonitions(methods_for_class, admonition_type="use_in")
|
||||
|
||||
@@ -362,7 +355,7 @@ class AdmonitionInserter:
|
||||
for idx, value in list(enumerate(lines)):
|
||||
if value.startswith(
|
||||
(
|
||||
".. seealso:",
|
||||
# ".. seealso:",
|
||||
# The docstring contains heading "Examples:", but Sphinx will have it converted
|
||||
# to ".. admonition: Examples":
|
||||
".. admonition:: Examples",
|
||||
@@ -435,12 +428,12 @@ class AdmonitionInserter:
|
||||
return admonition_for_class
|
||||
|
||||
@staticmethod
|
||||
def _generate_class_name_for_link(cls: type) -> str:
|
||||
def _generate_class_name_for_link(cls_: type) -> str:
|
||||
"""Generates class name that can be used in a ReST link."""
|
||||
|
||||
# Check for potential presence of ".ext.", we will need to keep it.
|
||||
ext = ".ext" if ".ext." in str(cls) else ""
|
||||
return f"telegram{ext}.{cls.__name__}"
|
||||
ext = ".ext" if ".ext." in str(cls_) else ""
|
||||
return f"telegram{ext}.{cls_.__name__}"
|
||||
|
||||
def _generate_link_to_method(self, method_name: str, cls: type) -> str:
|
||||
"""Generates a ReST link to a method of a telegram class."""
|
||||
@@ -448,19 +441,22 @@ class AdmonitionInserter:
|
||||
return f":meth:`{self._generate_class_name_for_link(cls)}.{method_name}`"
|
||||
|
||||
@staticmethod
|
||||
def _iter_subclasses(cls: type) -> Iterator:
|
||||
def _iter_subclasses(cls_: type) -> Iterator:
|
||||
if not hasattr(cls_, "__subclasses__") or cls_ is telegram.TelegramObject:
|
||||
return iter([])
|
||||
return (
|
||||
# exclude private classes
|
||||
c
|
||||
for c in cls.__subclasses__()
|
||||
for c in cls_.__subclasses__()
|
||||
if not str(c).split(".")[-1].startswith("_")
|
||||
)
|
||||
|
||||
def _resolve_arg_and_add_link(
|
||||
self,
|
||||
arg: Any,
|
||||
dict_of_methods_for_class: defaultdict,
|
||||
link: str,
|
||||
type_hints: dict[str, type],
|
||||
resolve_nested_type_vars: bool = True,
|
||||
) -> None:
|
||||
"""A helper method. Tries to resolve the arg into a valid class. In case of success,
|
||||
adds the link (to a method, attribute, or property) for that class' and its subclasses'
|
||||
@@ -468,7 +464,9 @@ class AdmonitionInserter:
|
||||
|
||||
**Modifies dictionary in place.**
|
||||
"""
|
||||
for cls in self._resolve_arg(arg):
|
||||
type_hints.pop("self", None)
|
||||
|
||||
for cls in self._resolve_arg(type_hints, resolve_nested_type_vars):
|
||||
# When trying to resolve an argument from args or return annotation,
|
||||
# the method _resolve_arg returns None if nothing could be resolved.
|
||||
# Also, if class was resolved correctly, "telegram" will definitely be in its str().
|
||||
@@ -480,88 +478,67 @@ class AdmonitionInserter:
|
||||
for subclass in self._iter_subclasses(cls):
|
||||
dict_of_methods_for_class[subclass].add(link)
|
||||
|
||||
def _resolve_arg(self, arg: Any) -> Iterator[Union[type, None]]:
|
||||
def _resolve_arg(
|
||||
self,
|
||||
type_hints: dict[str, type],
|
||||
resolve_nested_type_vars: bool,
|
||||
) -> list[type]:
|
||||
"""Analyzes an argument of a method and recursively yields classes that the argument
|
||||
or its sub-arguments (in cases like Union[...]) belong to, if they can be resolved to
|
||||
telegram or telegram.ext classes.
|
||||
|
||||
Args:
|
||||
type_hints: A dictionary of argument names and their types.
|
||||
resolve_nested_type_vars: If True, nested type variables (like Application[BT, …])
|
||||
will be resolved to their actual classes. If False, only the outermost type
|
||||
variable will be resolved. *Only* affects ptb classes, not built-in types.
|
||||
Useful for checking the return type of methods, where nested type variables
|
||||
are not really useful.
|
||||
|
||||
Raises `NotImplementedError`.
|
||||
"""
|
||||
|
||||
origin = typing.get_origin(arg)
|
||||
def _is_ptb_class(cls: type) -> bool:
|
||||
if not hasattr(cls, "__module__"):
|
||||
return False
|
||||
return cls.__module__.startswith("telegram")
|
||||
|
||||
if (
|
||||
origin in (collections.abc.Callable, typing.IO)
|
||||
or arg is None
|
||||
# no other check available (by type or origin) for these:
|
||||
or str(type(arg)) in ("<class 'typing._SpecialForm'>", "<class 'ellipsis'>")
|
||||
):
|
||||
pass
|
||||
# will be edited in place
|
||||
telegram_classes = set()
|
||||
|
||||
# RECURSIVE CALLS
|
||||
# for cases like Union[Sequence....
|
||||
elif origin in (
|
||||
Union,
|
||||
collections.abc.Coroutine,
|
||||
collections.abc.Sequence,
|
||||
):
|
||||
for sub_arg in typing.get_args(arg):
|
||||
yield from self._resolve_arg(sub_arg)
|
||||
def recurse_type(type_, is_recursed_from_ptb_class: bool):
|
||||
next_is_recursed_from_ptb_class = is_recursed_from_ptb_class or _is_ptb_class(type_)
|
||||
|
||||
elif isinstance(arg, typing.TypeVar):
|
||||
# gets access to the "bound=..." parameter
|
||||
yield from self._resolve_arg(arg.__bound__)
|
||||
# END RECURSIVE CALLS
|
||||
if hasattr(type_, "__origin__"): # For generic types like Union, List, etc.
|
||||
# Make sure it's not a telegram.ext generic type (e.g. ContextTypes[...])
|
||||
org = typing.get_origin(type_)
|
||||
if "telegram.ext" in str(org):
|
||||
telegram_classes.add(org)
|
||||
|
||||
elif isinstance(arg, typing.ForwardRef):
|
||||
m = self.FORWARD_REF_PATTERN.match(str(arg))
|
||||
# We're sure it's a ForwardRef, so, unless it belongs to known exceptions,
|
||||
# the class must be resolved.
|
||||
# If it isn't resolved, we'll have the program throw an exception to be sure.
|
||||
try:
|
||||
cls = self._resolve_class(m.group("class_name"))
|
||||
except AttributeError as exc:
|
||||
# skip known ForwardRef's that need not be resolved to a Telegram class
|
||||
if self.FORWARD_REF_SKIP_PATTERN.match(str(arg)):
|
||||
pass
|
||||
else:
|
||||
raise NotImplementedError(f"Could not process ForwardRef: {arg}") from exc
|
||||
else:
|
||||
yield cls
|
||||
args = typing.get_args(type_)
|
||||
for arg in args:
|
||||
recurse_type(arg, next_is_recursed_from_ptb_class)
|
||||
elif isinstance(type_, typing.TypeVar) and (
|
||||
resolve_nested_type_vars or not is_recursed_from_ptb_class
|
||||
):
|
||||
# gets access to the "bound=..." parameter
|
||||
recurse_type(type_.__bound__, next_is_recursed_from_ptb_class)
|
||||
elif inspect.isclass(type_) and "telegram" in inspect.getmodule(type_).__name__:
|
||||
telegram_classes.add(type_)
|
||||
elif isinstance(type_, typing.ForwardRef):
|
||||
# Resolving ForwardRef is not easy. https://peps.python.org/pep-0749/ will
|
||||
# hopefully make it better by introducing typing.resolve_forward_ref() in py3.14
|
||||
# but that's not there yet
|
||||
# So for now we fall back to a best effort approach of guessing if the class is
|
||||
# available in tg or tg.ext
|
||||
with contextlib.suppress(AttributeError):
|
||||
telegram_classes.add(self._resolve_class(type_.__forward_arg__))
|
||||
|
||||
# For custom generics like telegram.ext._application.Application[~BT, ~CCT, ~UD...].
|
||||
# This must come before the check for isinstance(type) because GenericAlias can also be
|
||||
# recognized as type if it belongs to <class 'types.GenericAlias'>.
|
||||
elif str(type(arg)) in (
|
||||
"<class 'typing._GenericAlias'>",
|
||||
"<class 'types.GenericAlias'>",
|
||||
"<class 'typing._LiteralGenericAlias'>",
|
||||
):
|
||||
if "telegram" in str(arg):
|
||||
# get_origin() of telegram.ext._application.Application[~BT, ~CCT, ~UD...]
|
||||
# will produce <class 'telegram.ext._application.Application'>
|
||||
yield origin
|
||||
for type_hint in type_hints.values():
|
||||
if type_hint is not None:
|
||||
recurse_type(type_hint, False)
|
||||
|
||||
elif isinstance(arg, type):
|
||||
if "telegram" in str(arg):
|
||||
yield arg
|
||||
|
||||
# For some reason "InlineQueryResult", "InputMedia" & some others are currently not
|
||||
# recognized as ForwardRefs and are identified as plain strings.
|
||||
elif isinstance(arg, str):
|
||||
# args like "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]" can be recognized as strings.
|
||||
# Remove whatever is in the square brackets because it doesn't need to be parsed.
|
||||
arg = re.sub(r"\[.+]", "", arg)
|
||||
|
||||
cls = self._resolve_class(arg)
|
||||
# Here we don't want an exception to be thrown since we're not sure it's ForwardRef
|
||||
if cls is not None:
|
||||
yield cls
|
||||
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
f"Cannot process argument {arg} of type {type(arg)} (origin {origin})"
|
||||
)
|
||||
return list(telegram_classes)
|
||||
|
||||
@staticmethod
|
||||
def _resolve_class(name: str) -> Union[type, None]:
|
||||
@@ -581,16 +558,14 @@ class AdmonitionInserter:
|
||||
f"telegram.ext.{name}",
|
||||
f"telegram.ext.filters.{name}",
|
||||
):
|
||||
try:
|
||||
return eval(option)
|
||||
# NameError will be raised if trying to eval just name and it doesn't work, e.g.
|
||||
# "Name 'ApplicationBuilder' is not defined".
|
||||
# AttributeError will be raised if trying to e.g. eval f"telegram.{name}" when the
|
||||
# class denoted by `name` actually belongs to `telegram.ext`:
|
||||
# "module 'telegram' has no attribute 'ApplicationBuilder'".
|
||||
# If neither option works, this is not a PTB class.
|
||||
except (NameError, AttributeError):
|
||||
continue
|
||||
with contextlib.suppress(NameError, AttributeError):
|
||||
return eval(option)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -187,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]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -15,7 +15,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 datetime
|
||||
import datetime as dtm
|
||||
from enum import Enum
|
||||
|
||||
from docutils.nodes import Element
|
||||
@@ -75,7 +75,7 @@ class TGConstXRefRole(PyXRefRole):
|
||||
):
|
||||
return str(value), target
|
||||
if (
|
||||
isinstance(value, datetime.datetime)
|
||||
isinstance(value, dtm.datetime)
|
||||
and value == telegram.constants.ZERO_DATE
|
||||
and target in ("telegram.constants.ZERO_DATE",)
|
||||
):
|
||||
|
||||
@@ -61,5 +61,5 @@
|
||||
}
|
||||
.admonition.returned-in > ul, .admonition.available-in > ul, .admonition.use-in > ul, .admonition.shortcuts > ul {
|
||||
max-height: 200px;
|
||||
overflow-y: scroll;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
+6
-1
@@ -13,7 +13,7 @@ sys.path.insert(0, str(Path("../..").resolve().absolute()))
|
||||
# -- General configuration ------------------------------------------------
|
||||
# General information about the project.
|
||||
project = "python-telegram-bot"
|
||||
copyright = "2015-2024, Leandro Toledo"
|
||||
copyright = "2015-2025, Leandro Toledo"
|
||||
author = "Leandro Toledo"
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
@@ -111,6 +111,11 @@ linkcheck_ignore = [
|
||||
# Anchors are apparently inserted by GitHub dynamically, so let's skip checking them
|
||||
"https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples#",
|
||||
r"https://github\.com/python-telegram-bot/python-telegram-bot/wiki/[\w\-_,]+\#",
|
||||
# The LGPL license link regularly causes network errors for some reason
|
||||
re.escape("https://www.gnu.org/licenses/lgpl-3.0.html"),
|
||||
# The doc-fixes branch may not always exist - doesn't matter, we only link to it from the
|
||||
# contributing guide
|
||||
re.escape("https://docs.python-telegram-bot.org/en/doc-fixes"),
|
||||
]
|
||||
linkcheck_allowed_redirects = {
|
||||
# Redirects to the default version are okay
|
||||
|
||||
@@ -183,6 +183,29 @@
|
||||
</details>
|
||||
<br>
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<details>
|
||||
<summary>Verification on behalf of an organization</summary>
|
||||
|
||||
.. list-table::
|
||||
:align: left
|
||||
:widths: 1 4
|
||||
|
||||
* - :meth:`~telegram.Bot.verify_chat`
|
||||
- Used for verifying a chat
|
||||
* - :meth:`~telegram.Bot.verify_user`
|
||||
- Used for verifying a user
|
||||
* - :meth:`~telegram.Bot.remove_chat_verification`
|
||||
- Used for removing the verification from a chat
|
||||
* - :meth:`~telegram.Bot.remove_user_verification`
|
||||
- Used for removing the verification from a user
|
||||
|
||||
.. raw:: html
|
||||
|
||||
</details>
|
||||
<br>
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<details>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
AffiliateInfo
|
||||
=============
|
||||
|
||||
.. autoclass:: telegram.AffiliateInfo
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -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__
|
||||
|
||||
@@ -9,6 +9,7 @@ Your bot can accept payments from Telegram users. Please see the `introduction t
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
telegram.affiliateinfo
|
||||
telegram.invoice
|
||||
telegram.labeledprice
|
||||
telegram.orderinfo
|
||||
@@ -25,6 +26,8 @@ Your bot can accept payments from Telegram users. Please see the `introduction t
|
||||
telegram.startransactions
|
||||
telegram.successfulpayment
|
||||
telegram.transactionpartner
|
||||
telegram.transactionpartneraffiliateprogram
|
||||
telegram.transactionpartnerchat
|
||||
telegram.transactionpartnerfragment
|
||||
telegram.transactionpartnerother
|
||||
telegram.transactionpartnertelegramads
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
TransactionPartnerAffiliateProgram
|
||||
===================================
|
||||
|
||||
.. autoclass:: telegram.TransactionPartnerAffiliateProgram
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,7 @@
|
||||
TransactionPartnerChat
|
||||
======================
|
||||
|
||||
.. autoclass:: telegram.TransactionPartnerChat
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TransactionPartner
|
||||
@@ -96,4 +96,8 @@
|
||||
|
||||
.. |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.
|
||||
.. |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.
|
||||
|
||||
.. |org-verify| replace:: `on behalf of the organization <https://telegram.org/verify#third-party-verification>`__
|
||||
|
||||
.. |time-period-input| replace:: :class:`datetime.timedelta` objects are accepted in addition to plain :obj:`int` values.
|
||||
|
||||
@@ -61,9 +61,9 @@ async def start_with_shipping_callback(update: Update, context: ContextTypes.DEF
|
||||
title,
|
||||
description,
|
||||
payload,
|
||||
PAYMENT_PROVIDER_TOKEN,
|
||||
currency,
|
||||
prices,
|
||||
provider_token=PAYMENT_PROVIDER_TOKEN,
|
||||
need_name=True,
|
||||
need_phone_number=True,
|
||||
need_email=True,
|
||||
@@ -90,7 +90,13 @@ async def start_without_shipping_callback(
|
||||
# optionally pass need_name=True, need_phone_number=True,
|
||||
# need_email=True, need_shipping_address=True, is_flexible=True
|
||||
await context.bot.send_invoice(
|
||||
chat_id, title, description, payload, PAYMENT_PROVIDER_TOKEN, currency, prices
|
||||
chat_id,
|
||||
title,
|
||||
description,
|
||||
payload,
|
||||
currency,
|
||||
prices,
|
||||
provider_token=PAYMENT_PROVIDER_TOKEN,
|
||||
)
|
||||
|
||||
|
||||
|
||||
+7
-8
@@ -10,7 +10,7 @@ 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"] }
|
||||
license-files = ["LICENSE", "LICENSE.dual", "LICENSE.lesser"]
|
||||
authors = [
|
||||
{ name = "Leandro Toledo", email = "devs@python-telegram-bot.org" }
|
||||
]
|
||||
@@ -76,9 +76,7 @@ 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",
|
||||
"APScheduler>=3.10.4,<3.12.0",
|
||||
]
|
||||
passport = [
|
||||
"cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=39.0.1",
|
||||
@@ -86,7 +84,7 @@ passport = [
|
||||
"cffi >= 1.17.0rc1; python_version > '3.12'"
|
||||
]
|
||||
rate-limiter = [
|
||||
"aiolimiter~=1.1.0",
|
||||
"aiolimiter>=1.1,<1.3",
|
||||
]
|
||||
socks = [
|
||||
"httpx[socks]",
|
||||
@@ -149,7 +147,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]
|
||||
@@ -180,8 +179,8 @@ markers = [
|
||||
"req",
|
||||
]
|
||||
asyncio_mode = "auto"
|
||||
log_format = "%(funcName)s - Line %(lineno)d - %(message)s"
|
||||
# log_level = "DEBUG" # uncomment to see DEBUG logs
|
||||
log_cli_format = "%(funcName)s - Line %(lineno)d - %(message)s"
|
||||
# log_cli_level = "DEBUG" # uncomment to see DEBUG logs
|
||||
|
||||
# MYPY:
|
||||
[tool.mypy]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
build
|
||||
|
||||
# For the test suite
|
||||
pytest==8.3.3
|
||||
pytest==8.3.4
|
||||
|
||||
# needed because pytest doesn't come with native support for coroutines as tests
|
||||
pytest-asyncio==0.21.2
|
||||
@@ -16,4 +16,8 @@ pytest-xdist==3.6.1
|
||||
flaky>=3.8.1
|
||||
|
||||
# used in test_official for parsing tg docs
|
||||
beautifulsoup4
|
||||
beautifulsoup4
|
||||
|
||||
# For testing with timezones. Might not be needed on all systems, but to ensure that unit tests
|
||||
# run correctly on all systems, we include it here.
|
||||
tzdata
|
||||
+18
-10
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
__author__ = "devs@python-telegram-bot.org"
|
||||
__all__ = (
|
||||
"AffiliateInfo",
|
||||
"Animation",
|
||||
"Audio",
|
||||
"BackgroundFill",
|
||||
@@ -236,6 +237,8 @@ __all__ = (
|
||||
"TelegramObject",
|
||||
"TextQuote",
|
||||
"TransactionPartner",
|
||||
"TransactionPartnerAffiliateProgram",
|
||||
"TransactionPartnerChat",
|
||||
"TransactionPartnerFragment",
|
||||
"TransactionPartnerOther",
|
||||
"TransactionPartnerTelegramAds",
|
||||
@@ -269,6 +272,18 @@ __all__ = (
|
||||
"warnings",
|
||||
)
|
||||
|
||||
from telegram._payment.stars.startransactions import StarTransaction, StarTransactions
|
||||
from telegram._payment.stars.transactionpartner import (
|
||||
TransactionPartner,
|
||||
TransactionPartnerAffiliateProgram,
|
||||
TransactionPartnerChat,
|
||||
TransactionPartnerFragment,
|
||||
TransactionPartnerOther,
|
||||
TransactionPartnerTelegramAds,
|
||||
TransactionPartnerTelegramApi,
|
||||
TransactionPartnerUser,
|
||||
)
|
||||
|
||||
from . import _version, constants, error, helpers, request, warnings
|
||||
from ._birthdate import Birthdate
|
||||
from ._bot import Bot
|
||||
@@ -468,19 +483,12 @@ from ._payment.refundedpayment import RefundedPayment
|
||||
from ._payment.shippingaddress import ShippingAddress
|
||||
from ._payment.shippingoption import ShippingOption
|
||||
from ._payment.shippingquery import ShippingQuery
|
||||
from ._payment.stars import (
|
||||
from ._payment.stars.affiliateinfo import AffiliateInfo
|
||||
from ._payment.stars.revenuewithdrawalstate import (
|
||||
RevenueWithdrawalState,
|
||||
RevenueWithdrawalStateFailed,
|
||||
RevenueWithdrawalStatePending,
|
||||
RevenueWithdrawalStateSucceeded,
|
||||
StarTransaction,
|
||||
StarTransactions,
|
||||
TransactionPartner,
|
||||
TransactionPartnerFragment,
|
||||
TransactionPartnerOther,
|
||||
TransactionPartnerTelegramAds,
|
||||
TransactionPartnerTelegramApi,
|
||||
TransactionPartnerUser,
|
||||
)
|
||||
from ._payment.successfulpayment import SuccessfulPayment
|
||||
from ._poll import InputPollOption, Poll, PollAnswer, PollOption
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# !/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -17,7 +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/].
|
||||
"""This module contains an object that represents a Telegram Birthday."""
|
||||
from datetime import date
|
||||
import datetime as dtm
|
||||
from typing import Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
@@ -70,7 +70,7 @@ class Birthdate(TelegramObject):
|
||||
|
||||
self._freeze()
|
||||
|
||||
def to_date(self, year: Optional[int] = None) -> date:
|
||||
def to_date(self, year: Optional[int] = None) -> dtm.date:
|
||||
"""Return the birthdate as a date object.
|
||||
|
||||
.. versionchanged:: 21.2
|
||||
@@ -89,4 +89,4 @@ class Birthdate(TelegramObject):
|
||||
"The `year` argument is required if the `year` attribute was not present."
|
||||
)
|
||||
|
||||
return date(year or self.year, self.month, self.day) # type: ignore[arg-type]
|
||||
return dtm.date(year or self.year, self.month, self.day) # type: ignore[arg-type]
|
||||
|
||||
+489
-120
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -84,9 +84,7 @@ class BotCommandScope(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BotCommandScope"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "BotCommandScope":
|
||||
"""Converts JSON data to the appropriate :class:`BotCommandScope` object, i.e. takes
|
||||
care of selecting the correct subclass.
|
||||
|
||||
@@ -104,9 +102,6 @@ class BotCommandScope(TelegramObject):
|
||||
"""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
_class_mapping: dict[str, type[BotCommandScope]] = {
|
||||
cls.DEFAULT: BotCommandScopeDefault,
|
||||
cls.ALL_PRIVATE_CHATS: BotCommandScopeAllPrivateChats,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
+16
-42
@@ -2,7 +2,7 @@
|
||||
# pylint: disable=redefined-builtin
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -18,9 +18,8 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/]
|
||||
"""This module contains the Telegram Business related classes."""
|
||||
|
||||
import datetime as dtm
|
||||
from collections.abc import Sequence
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._chat import Chat
|
||||
@@ -28,7 +27,7 @@ from telegram._files.location import Location
|
||||
from telegram._files.sticker import Sticker
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
@@ -81,7 +80,7 @@ class BusinessConnection(TelegramObject):
|
||||
id: str,
|
||||
user: "User",
|
||||
user_chat_id: int,
|
||||
date: datetime,
|
||||
date: dtm.datetime,
|
||||
can_reply: bool,
|
||||
is_enabled: bool,
|
||||
*,
|
||||
@@ -91,7 +90,7 @@ class BusinessConnection(TelegramObject):
|
||||
self.id: str = id
|
||||
self.user: User = user
|
||||
self.user_chat_id: int = user_chat_id
|
||||
self.date: datetime = date
|
||||
self.date: dtm.datetime = date
|
||||
self.can_reply: bool = can_reply
|
||||
self.is_enabled: bool = is_enabled
|
||||
|
||||
@@ -107,20 +106,15 @@ class BusinessConnection(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BusinessConnection"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "BusinessConnection":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
|
||||
data["user"] = User.de_json(data.get("user"), bot)
|
||||
data["user"] = de_json_optional(data.get("user"), User, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -178,16 +172,11 @@ class BusinessMessagesDeleted(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BusinessMessagesDeleted"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "BusinessMessagesDeleted":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["chat"] = Chat.de_json(data.get("chat"), bot)
|
||||
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -237,16 +226,11 @@ class BusinessIntro(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BusinessIntro"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "BusinessIntro":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["sticker"] = Sticker.de_json(data.get("sticker"), bot)
|
||||
data["sticker"] = de_json_optional(data.get("sticker"), Sticker, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -291,16 +275,11 @@ class BusinessLocation(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BusinessLocation"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "BusinessLocation":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["location"] = Location.de_json(data.get("location"), bot)
|
||||
data["location"] = de_json_optional(data.get("location"), Location, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -440,17 +419,12 @@ class BusinessOpeningHours(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BusinessOpeningHours"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "BusinessOpeningHours":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["opening_hours"] = BusinessOpeningHoursInterval.de_list(
|
||||
data.get("opening_hours"), bot
|
||||
data["opening_hours"] = de_list_optional(
|
||||
data.get("opening_hours"), BusinessOpeningHoursInterval, bot
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
+10
-12
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -26,8 +26,9 @@ from telegram._files.location import Location
|
||||
from telegram._message import MaybeInaccessibleMessage, Message
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import JSONDict, ODVInput, ReplyMarkup
|
||||
from telegram._utils.types import JSONDict, ODVInput, ReplyMarkup, TimePeriod
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import (
|
||||
@@ -149,17 +150,12 @@ class CallbackQuery(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["CallbackQuery"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "CallbackQuery":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["from_user"] = User.de_json(data.pop("from", None), bot)
|
||||
data["message"] = Message.de_json(data.get("message"), bot)
|
||||
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
|
||||
data["message"] = de_json_optional(data.get("message"), Message, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -168,7 +164,7 @@ class CallbackQuery(TelegramObject):
|
||||
text: Optional[str] = None,
|
||||
show_alert: Optional[bool] = None,
|
||||
url: Optional[str] = None,
|
||||
cache_time: Optional[int] = None,
|
||||
cache_time: Optional[TimePeriod] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -475,7 +471,7 @@ class CallbackQuery(TelegramObject):
|
||||
horizontal_accuracy: Optional[float] = None,
|
||||
heading: Optional[int] = None,
|
||||
proximity_alert_radius: Optional[int] = None,
|
||||
live_period: Optional[int] = None,
|
||||
live_period: Optional[TimePeriod] = None,
|
||||
*,
|
||||
location: Optional[Location] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -835,6 +831,7 @@ class CallbackQuery(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
video_start_timestamp: Optional[int] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
@@ -868,6 +865,7 @@ class CallbackQuery(TelegramObject):
|
||||
chat_id=chat_id,
|
||||
caption=caption,
|
||||
parse_mode=parse_mode,
|
||||
video_start_timestamp=video_start_timestamp,
|
||||
caption_entities=caption_entities,
|
||||
disable_notification=disable_notification,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
|
||||
+110
-19
@@ -2,7 +2,7 @@
|
||||
# pylint: disable=redefined-builtin
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -18,8 +18,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 an object that represents a Telegram Chat."""
|
||||
import datetime as dtm
|
||||
from collections.abc import Sequence
|
||||
from datetime import datetime
|
||||
from html import escape
|
||||
from typing import TYPE_CHECKING, Final, Optional, Union
|
||||
|
||||
@@ -31,7 +31,14 @@ from telegram._reaction import ReactionType
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils import enum
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup
|
||||
from telegram._utils.types import (
|
||||
CorrectOptionID,
|
||||
FileInput,
|
||||
JSONDict,
|
||||
ODVInput,
|
||||
ReplyMarkup,
|
||||
TimePeriod,
|
||||
)
|
||||
from telegram.helpers import escape_markdown
|
||||
from telegram.helpers import mention_html as helpers_mention_html
|
||||
from telegram.helpers import mention_markdown as helpers_mention_markdown
|
||||
@@ -384,7 +391,7 @@ class _ChatBase(TelegramObject):
|
||||
self,
|
||||
user_id: int,
|
||||
revoke_messages: Optional[bool] = None,
|
||||
until_date: Optional[Union[int, datetime]] = None,
|
||||
until_date: Optional[Union[int, dtm.datetime]] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -656,7 +663,7 @@ class _ChatBase(TelegramObject):
|
||||
self,
|
||||
user_id: int,
|
||||
permissions: ChatPermissions,
|
||||
until_date: Optional[Union[int, datetime]] = None,
|
||||
until_date: Optional[Union[int, dtm.datetime]] = None,
|
||||
use_independent_chat_permissions: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -1339,7 +1346,7 @@ class _ChatBase(TelegramObject):
|
||||
async def send_audio(
|
||||
self,
|
||||
audio: Union[FileInput, "Audio"],
|
||||
duration: Optional[int] = None,
|
||||
duration: Optional[TimePeriod] = None,
|
||||
performer: Optional[str] = None,
|
||||
title: Optional[str] = None,
|
||||
caption: Optional[str] = None,
|
||||
@@ -1569,9 +1576,9 @@ class _ChatBase(TelegramObject):
|
||||
title: str,
|
||||
description: str,
|
||||
payload: str,
|
||||
provider_token: Optional[str],
|
||||
currency: str,
|
||||
prices: Sequence["LabeledPrice"],
|
||||
provider_token: Optional[str] = None,
|
||||
start_parameter: Optional[str] = None,
|
||||
photo_url: Optional[str] = None,
|
||||
photo_size: Optional[int] = None,
|
||||
@@ -1668,7 +1675,7 @@ class _ChatBase(TelegramObject):
|
||||
longitude: Optional[float] = None,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
live_period: Optional[int] = None,
|
||||
live_period: Optional[TimePeriod] = None,
|
||||
horizontal_accuracy: Optional[float] = None,
|
||||
heading: Optional[int] = None,
|
||||
proximity_alert_radius: Optional[int] = None,
|
||||
@@ -1727,7 +1734,7 @@ class _ChatBase(TelegramObject):
|
||||
async def send_animation(
|
||||
self,
|
||||
animation: Union[FileInput, "Animation"],
|
||||
duration: Optional[int] = None,
|
||||
duration: Optional[TimePeriod] = None,
|
||||
width: Optional[int] = None,
|
||||
height: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
@@ -1915,7 +1922,7 @@ class _ChatBase(TelegramObject):
|
||||
async def send_video(
|
||||
self,
|
||||
video: Union[FileInput, "Video"],
|
||||
duration: Optional[int] = None,
|
||||
duration: Optional[TimePeriod] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
@@ -1933,6 +1940,8 @@ class _ChatBase(TelegramObject):
|
||||
message_effect_id: Optional[str] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
cover: Optional[FileInput] = None,
|
||||
start_timestamp: Optional[int] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1971,6 +1980,8 @@ class _ChatBase(TelegramObject):
|
||||
parse_mode=parse_mode,
|
||||
supports_streaming=supports_streaming,
|
||||
thumbnail=thumbnail,
|
||||
cover=cover,
|
||||
start_timestamp=start_timestamp,
|
||||
api_kwargs=api_kwargs,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
caption_entities=caption_entities,
|
||||
@@ -1987,7 +1998,7 @@ class _ChatBase(TelegramObject):
|
||||
async def send_video_note(
|
||||
self,
|
||||
video_note: Union[FileInput, "VideoNote"],
|
||||
duration: Optional[int] = None,
|
||||
duration: Optional[TimePeriod] = None,
|
||||
length: Optional[int] = None,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
@@ -2045,7 +2056,7 @@ class _ChatBase(TelegramObject):
|
||||
async def send_voice(
|
||||
self,
|
||||
voice: Union[FileInput, "Voice"],
|
||||
duration: Optional[int] = None,
|
||||
duration: Optional[TimePeriod] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
@@ -2115,8 +2126,8 @@ class _ChatBase(TelegramObject):
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
explanation: Optional[str] = None,
|
||||
explanation_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
open_period: Optional[int] = None,
|
||||
close_date: Optional[Union[int, datetime]] = None,
|
||||
open_period: Optional[TimePeriod] = None,
|
||||
close_date: Optional[Union[int, dtm.datetime]] = None,
|
||||
explanation_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
@@ -2192,6 +2203,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
video_start_timestamp: Optional[int] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2218,6 +2230,7 @@ class _ChatBase(TelegramObject):
|
||||
from_chat_id=from_chat_id,
|
||||
message_id=message_id,
|
||||
caption=caption,
|
||||
video_start_timestamp=video_start_timestamp,
|
||||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
disable_notification=disable_notification,
|
||||
@@ -2250,6 +2263,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
allow_paid_broadcast: Optional[bool] = None,
|
||||
video_start_timestamp: Optional[int] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2276,6 +2290,7 @@ class _ChatBase(TelegramObject):
|
||||
chat_id=chat_id,
|
||||
message_id=message_id,
|
||||
caption=caption,
|
||||
video_start_timestamp=video_start_timestamp,
|
||||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
disable_notification=disable_notification,
|
||||
@@ -2391,6 +2406,7 @@ class _ChatBase(TelegramObject):
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
video_start_timestamp: Optional[int] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2416,6 +2432,7 @@ class _ChatBase(TelegramObject):
|
||||
chat_id=self.id,
|
||||
from_chat_id=from_chat_id,
|
||||
message_id=message_id,
|
||||
video_start_timestamp=video_start_timestamp,
|
||||
disable_notification=disable_notification,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
@@ -2433,6 +2450,7 @@ class _ChatBase(TelegramObject):
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
video_start_timestamp: Optional[int] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2459,6 +2477,7 @@ class _ChatBase(TelegramObject):
|
||||
from_chat_id=self.id,
|
||||
chat_id=chat_id,
|
||||
message_id=message_id,
|
||||
video_start_timestamp=video_start_timestamp,
|
||||
disable_notification=disable_notification,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
@@ -2588,7 +2607,7 @@ class _ChatBase(TelegramObject):
|
||||
|
||||
async def create_invite_link(
|
||||
self,
|
||||
expire_date: Optional[Union[int, datetime]] = None,
|
||||
expire_date: Optional[Union[int, dtm.datetime]] = None,
|
||||
member_limit: Optional[int] = None,
|
||||
name: Optional[str] = None,
|
||||
creates_join_request: Optional[bool] = None,
|
||||
@@ -2632,7 +2651,7 @@ class _ChatBase(TelegramObject):
|
||||
async def edit_invite_link(
|
||||
self,
|
||||
invite_link: Union[str, "ChatInviteLink"],
|
||||
expire_date: Optional[Union[int, datetime]] = None,
|
||||
expire_date: Optional[Union[int, dtm.datetime]] = None,
|
||||
member_limit: Optional[int] = None,
|
||||
name: Optional[str] = None,
|
||||
creates_join_request: Optional[bool] = None,
|
||||
@@ -2708,7 +2727,7 @@ class _ChatBase(TelegramObject):
|
||||
|
||||
async def create_subscription_invite_link(
|
||||
self,
|
||||
subscription_period: int,
|
||||
subscription_period: TimePeriod,
|
||||
subscription_price: int,
|
||||
name: Optional[str] = None,
|
||||
*,
|
||||
@@ -3443,6 +3462,7 @@ class _ChatBase(TelegramObject):
|
||||
text: Optional[str] = None,
|
||||
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
text_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
pay_for_upgrade: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -3454,22 +3474,93 @@ class _ChatBase(TelegramObject):
|
||||
|
||||
await bot.send_gift(user_id=update.effective_chat.id, *args, **kwargs )
|
||||
|
||||
or::
|
||||
|
||||
await bot.send_gift(chat_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`.
|
||||
Will only work if the chat is a private or channel chat, see :attr:`type`.
|
||||
|
||||
.. versionadded:: 21.8
|
||||
|
||||
.. versionchanged:: 21.11
|
||||
|
||||
Added support for channel chats.
|
||||
|
||||
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,
|
||||
pay_for_upgrade=pay_for_upgrade,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
**{"chat_id" if self.type == Chat.CHANNEL else "user_id": self.id},
|
||||
)
|
||||
|
||||
async def verify(
|
||||
self,
|
||||
custom_description: 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,
|
||||
) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
await bot.verify_chat(chat_id=update.effective_chat.id, *args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.verify_chat`.
|
||||
|
||||
.. versionadded:: 21.10
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
"""
|
||||
return await self.get_bot().verify_chat(
|
||||
chat_id=self.id,
|
||||
custom_description=custom_description,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def remove_verification(
|
||||
self,
|
||||
*,
|
||||
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.remove_chat_verification(chat_id=update.effective_chat.id, *args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.remove_chat_verification`.
|
||||
|
||||
.. versionadded:: 21.10
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
"""
|
||||
return await self.get_bot().remove_chat_verification(
|
||||
chat_id=self.id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
+10
-25
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -24,7 +24,7 @@ from telegram import constants
|
||||
from telegram._files.document import Document
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils import enum
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.argumentparsing import de_json_optional, parse_sequence_arg
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -79,15 +79,10 @@ class BackgroundFill(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BackgroundFill"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "BackgroundFill":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
_class_mapping: dict[str, type[BackgroundFill]] = {
|
||||
cls.SOLID: BackgroundFillSolid,
|
||||
cls.GRADIENT: BackgroundFillGradient,
|
||||
@@ -270,15 +265,10 @@ class BackgroundType(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["BackgroundType"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "BackgroundType":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
_class_mapping: dict[str, type[BackgroundType]] = {
|
||||
cls.FILL: BackgroundTypeFill,
|
||||
cls.WALLPAPER: BackgroundTypeWallpaper,
|
||||
@@ -290,10 +280,10 @@ class BackgroundType(TelegramObject):
|
||||
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
|
||||
|
||||
if "fill" in data:
|
||||
data["fill"] = BackgroundFill.de_json(data.get("fill"), bot)
|
||||
data["fill"] = de_json_optional(data.get("fill"), BackgroundFill, bot)
|
||||
|
||||
if "document" in data:
|
||||
data["document"] = Document.de_json(data.get("document"), bot)
|
||||
data["document"] = de_json_optional(data.get("document"), Document, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -398,8 +388,8 @@ class BackgroundTypeWallpaper(BackgroundType):
|
||||
|
||||
class BackgroundTypePattern(BackgroundType):
|
||||
"""
|
||||
The background is a `PNG` or `TGV` (gzipped subset of `SVG` with `MIME` type
|
||||
`"application/x-tgwallpattern"`) pattern to be combined with the background fill
|
||||
The background is a ``.PNG`` or ``.TGV`` (gzipped subset of ``SVG`` with ``MIME`` type
|
||||
``"application/x-tgwallpattern"``) pattern to be combined with the background fill
|
||||
chosen by the user.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
@@ -533,15 +523,10 @@ class ChatBackground(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatBackground"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatBackground":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["type"] = BackgroundType.de_json(data.get("type"), bot)
|
||||
data["type"] = de_json_optional(data.get("type"), BackgroundType, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
+24
-50
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -17,9 +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 the classes that represent Telegram ChatBoosts."""
|
||||
|
||||
import datetime as dtm
|
||||
from collections.abc import Sequence
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Final, Optional
|
||||
|
||||
from telegram import constants
|
||||
@@ -27,7 +26,7 @@ from telegram._chat import Chat
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils import enum
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
@@ -111,15 +110,10 @@ class ChatBoostSource(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatBoostSource"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatBoostSource":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
_class_mapping: dict[str, type[ChatBoostSource]] = {
|
||||
cls.PREMIUM: ChatBoostSourcePremium,
|
||||
cls.GIFT_CODE: ChatBoostSourceGiftCode,
|
||||
@@ -130,7 +124,7 @@ class ChatBoostSource(TelegramObject):
|
||||
return _class_mapping[data.pop("source")].de_json(data=data, bot=bot)
|
||||
|
||||
if "user" in data:
|
||||
data["user"] = User.de_json(data.get("user"), bot)
|
||||
data["user"] = de_json_optional(data.get("user"), User, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -274,8 +268,8 @@ class ChatBoost(TelegramObject):
|
||||
def __init__(
|
||||
self,
|
||||
boost_id: str,
|
||||
add_date: datetime,
|
||||
expiration_date: datetime,
|
||||
add_date: dtm.datetime,
|
||||
expiration_date: dtm.datetime,
|
||||
source: ChatBoostSource,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -283,27 +277,22 @@ class ChatBoost(TelegramObject):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
self.boost_id: str = boost_id
|
||||
self.add_date: datetime = add_date
|
||||
self.expiration_date: datetime = expiration_date
|
||||
self.add_date: dtm.datetime = add_date
|
||||
self.expiration_date: dtm.datetime = expiration_date
|
||||
self.source: ChatBoostSource = source
|
||||
|
||||
self._id_attrs = (self.boost_id, self.add_date, self.expiration_date, self.source)
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatBoost"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatBoost":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["source"] = ChatBoostSource.de_json(data.get("source"), bot)
|
||||
data["source"] = de_json_optional(data.get("source"), ChatBoostSource, bot)
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
data["add_date"] = from_timestamp(data["add_date"], tzinfo=loc_tzinfo)
|
||||
data["expiration_date"] = from_timestamp(data["expiration_date"], tzinfo=loc_tzinfo)
|
||||
data["add_date"] = from_timestamp(data.get("add_date"), tzinfo=loc_tzinfo)
|
||||
data["expiration_date"] = from_timestamp(data.get("expiration_date"), tzinfo=loc_tzinfo)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -343,17 +332,12 @@ class ChatBoostUpdated(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatBoostUpdated"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatBoostUpdated":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["chat"] = Chat.de_json(data.get("chat"), bot)
|
||||
data["boost"] = ChatBoost.de_json(data.get("boost"), bot)
|
||||
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
|
||||
data["boost"] = de_json_optional(data.get("boost"), ChatBoost, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -386,7 +370,7 @@ class ChatBoostRemoved(TelegramObject):
|
||||
self,
|
||||
chat: Chat,
|
||||
boost_id: str,
|
||||
remove_date: datetime,
|
||||
remove_date: dtm.datetime,
|
||||
source: ChatBoostSource,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -395,26 +379,21 @@ class ChatBoostRemoved(TelegramObject):
|
||||
|
||||
self.chat: Chat = chat
|
||||
self.boost_id: str = boost_id
|
||||
self.remove_date: datetime = remove_date
|
||||
self.remove_date: dtm.datetime = remove_date
|
||||
self.source: ChatBoostSource = source
|
||||
|
||||
self._id_attrs = (self.chat, self.boost_id, self.remove_date, self.source)
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatBoostRemoved"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatBoostRemoved":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["chat"] = Chat.de_json(data.get("chat"), bot)
|
||||
data["source"] = ChatBoostSource.de_json(data.get("source"), bot)
|
||||
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
|
||||
data["source"] = de_json_optional(data.get("source"), ChatBoostSource, bot)
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
data["remove_date"] = from_timestamp(data["remove_date"], tzinfo=loc_tzinfo)
|
||||
data["remove_date"] = from_timestamp(data.get("remove_date"), tzinfo=loc_tzinfo)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -451,15 +430,10 @@ class UserChatBoosts(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["UserChatBoosts"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "UserChatBoosts":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["boosts"] = ChatBoost.de_list(data.get("boosts"), bot)
|
||||
data["boosts"] = de_list_optional(data.get("boosts"), ChatBoost, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
+32
-22
@@ -2,7 +2,7 @@
|
||||
# pylint: disable=redefined-builtin
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -18,8 +18,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 an object that represents a Telegram ChatFullInfo."""
|
||||
import datetime as dtm
|
||||
from collections.abc import Sequence
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._birthdate import Birthdate
|
||||
@@ -28,7 +28,7 @@ from telegram._chatlocation import ChatLocation
|
||||
from telegram._chatpermissions import ChatPermissions
|
||||
from telegram._files.chatphoto import ChatPhoto
|
||||
from telegram._reaction import ReactionType
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
@@ -200,6 +200,9 @@ class ChatFullInfo(_ChatBase):
|
||||
sent or forwarded to the channel chat. The field is available only for channel chats.
|
||||
|
||||
.. versionadded:: 21.4
|
||||
can_send_gift (:obj:`bool`, optional): :obj:`True`, if gifts can be sent to the chat.
|
||||
|
||||
.. versionadded:: 21.11
|
||||
|
||||
Attributes:
|
||||
id (:obj:`int`): Unique identifier for this chat.
|
||||
@@ -354,6 +357,9 @@ class ChatFullInfo(_ChatBase):
|
||||
sent or forwarded to the channel chat. The field is available only for channel chats.
|
||||
|
||||
.. versionadded:: 21.4
|
||||
can_send_gift (:obj:`bool`): Optional. :obj:`True`, if gifts can be sent to the chat.
|
||||
|
||||
.. versionadded:: 21.11
|
||||
|
||||
.. _accent colors: https://core.telegram.org/bots/api#accent-colors
|
||||
.. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups
|
||||
@@ -369,6 +375,7 @@ class ChatFullInfo(_ChatBase):
|
||||
"business_intro",
|
||||
"business_location",
|
||||
"business_opening_hours",
|
||||
"can_send_gift",
|
||||
"can_send_paid_media",
|
||||
"can_set_sticker_set",
|
||||
"custom_emoji_sticker_set_name",
|
||||
@@ -422,7 +429,7 @@ class ChatFullInfo(_ChatBase):
|
||||
profile_accent_color_id: Optional[int] = None,
|
||||
profile_background_custom_emoji_id: Optional[str] = None,
|
||||
emoji_status_custom_emoji_id: Optional[str] = None,
|
||||
emoji_status_expiration_date: Optional[datetime] = None,
|
||||
emoji_status_expiration_date: Optional[dtm.datetime] = None,
|
||||
bio: Optional[str] = None,
|
||||
has_private_forwards: Optional[bool] = None,
|
||||
has_restricted_voice_and_video_messages: Optional[bool] = None,
|
||||
@@ -445,6 +452,7 @@ class ChatFullInfo(_ChatBase):
|
||||
linked_chat_id: Optional[int] = None,
|
||||
location: Optional[ChatLocation] = None,
|
||||
can_send_paid_media: Optional[bool] = None,
|
||||
can_send_gift: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -486,7 +494,9 @@ class ChatFullInfo(_ChatBase):
|
||||
)
|
||||
self.active_usernames: tuple[str, ...] = parse_sequence_arg(active_usernames)
|
||||
self.emoji_status_custom_emoji_id: Optional[str] = emoji_status_custom_emoji_id
|
||||
self.emoji_status_expiration_date: Optional[datetime] = emoji_status_expiration_date
|
||||
self.emoji_status_expiration_date: Optional[dtm.datetime] = (
|
||||
emoji_status_expiration_date
|
||||
)
|
||||
self.has_aggressive_anti_spam_enabled: Optional[bool] = (
|
||||
has_aggressive_anti_spam_enabled
|
||||
)
|
||||
@@ -508,17 +518,13 @@ class ChatFullInfo(_ChatBase):
|
||||
self.business_location: Optional[BusinessLocation] = business_location
|
||||
self.business_opening_hours: Optional[BusinessOpeningHours] = business_opening_hours
|
||||
self.can_send_paid_media: Optional[bool] = can_send_paid_media
|
||||
self.can_send_gift: Optional[bool] = can_send_gift
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatFullInfo"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatFullInfo":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
@@ -526,7 +532,7 @@ class ChatFullInfo(_ChatBase):
|
||||
data.get("emoji_status_expiration_date"), tzinfo=loc_tzinfo
|
||||
)
|
||||
|
||||
data["photo"] = ChatPhoto.de_json(data.get("photo"), bot)
|
||||
data["photo"] = de_json_optional(data.get("photo"), ChatPhoto, bot)
|
||||
|
||||
from telegram import ( # pylint: disable=import-outside-toplevel
|
||||
BusinessIntro,
|
||||
@@ -535,16 +541,20 @@ class ChatFullInfo(_ChatBase):
|
||||
Message,
|
||||
)
|
||||
|
||||
data["pinned_message"] = Message.de_json(data.get("pinned_message"), bot)
|
||||
data["permissions"] = ChatPermissions.de_json(data.get("permissions"), bot)
|
||||
data["location"] = ChatLocation.de_json(data.get("location"), bot)
|
||||
data["available_reactions"] = ReactionType.de_list(data.get("available_reactions"), bot)
|
||||
data["birthdate"] = Birthdate.de_json(data.get("birthdate"), bot)
|
||||
data["personal_chat"] = Chat.de_json(data.get("personal_chat"), bot)
|
||||
data["business_intro"] = BusinessIntro.de_json(data.get("business_intro"), bot)
|
||||
data["business_location"] = BusinessLocation.de_json(data.get("business_location"), bot)
|
||||
data["business_opening_hours"] = BusinessOpeningHours.de_json(
|
||||
data.get("business_opening_hours"), bot
|
||||
data["pinned_message"] = de_json_optional(data.get("pinned_message"), Message, bot)
|
||||
data["permissions"] = de_json_optional(data.get("permissions"), ChatPermissions, bot)
|
||||
data["location"] = de_json_optional(data.get("location"), ChatLocation, bot)
|
||||
data["available_reactions"] = de_list_optional(
|
||||
data.get("available_reactions"), ReactionType, bot
|
||||
)
|
||||
data["birthdate"] = de_json_optional(data.get("birthdate"), Birthdate, bot)
|
||||
data["personal_chat"] = de_json_optional(data.get("personal_chat"), Chat, bot)
|
||||
data["business_intro"] = de_json_optional(data.get("business_intro"), BusinessIntro, bot)
|
||||
data["business_location"] = de_json_optional(
|
||||
data.get("business_location"), BusinessLocation, bot
|
||||
)
|
||||
data["business_opening_hours"] = de_json_optional(
|
||||
data.get("business_opening_hours"), BusinessOpeningHours, bot
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -17,11 +17,12 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents an invite link for a chat."""
|
||||
import datetime
|
||||
import datetime as dtm
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
@@ -139,7 +140,7 @@ class ChatInviteLink(TelegramObject):
|
||||
creates_join_request: bool,
|
||||
is_primary: bool,
|
||||
is_revoked: bool,
|
||||
expire_date: Optional[datetime.datetime] = None,
|
||||
expire_date: Optional[dtm.datetime] = None,
|
||||
member_limit: Optional[int] = None,
|
||||
name: Optional[str] = None,
|
||||
pending_join_request_count: Optional[int] = None,
|
||||
@@ -157,7 +158,7 @@ class ChatInviteLink(TelegramObject):
|
||||
self.is_revoked: bool = is_revoked
|
||||
|
||||
# Optionals
|
||||
self.expire_date: Optional[datetime.datetime] = expire_date
|
||||
self.expire_date: Optional[dtm.datetime] = expire_date
|
||||
self.member_limit: Optional[int] = member_limit
|
||||
self.name: Optional[str] = name
|
||||
self.pending_join_request_count: Optional[int] = (
|
||||
@@ -177,19 +178,14 @@ class ChatInviteLink(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatInviteLink"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatInviteLink":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["creator"] = User.de_json(data.get("creator"), bot)
|
||||
data["creator"] = de_json_optional(data.get("creator"), User, bot)
|
||||
data["expire_date"] = from_timestamp(data.get("expire_date", None), tzinfo=loc_tzinfo)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -17,13 +17,14 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram ChatJoinRequest."""
|
||||
import datetime
|
||||
import datetime as dtm
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._chat import Chat
|
||||
from telegram._chatinvitelink import ChatInviteLink
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import JSONDict, ODVInput
|
||||
@@ -106,7 +107,7 @@ class ChatJoinRequest(TelegramObject):
|
||||
self,
|
||||
chat: Chat,
|
||||
from_user: User,
|
||||
date: datetime.datetime,
|
||||
date: dtm.datetime,
|
||||
user_chat_id: int,
|
||||
bio: Optional[str] = None,
|
||||
invite_link: Optional[ChatInviteLink] = None,
|
||||
@@ -117,7 +118,7 @@ class ChatJoinRequest(TelegramObject):
|
||||
# Required
|
||||
self.chat: Chat = chat
|
||||
self.from_user: User = from_user
|
||||
self.date: datetime.datetime = date
|
||||
self.date: dtm.datetime = date
|
||||
self.user_chat_id: int = user_chat_id
|
||||
|
||||
# Optionals
|
||||
@@ -129,22 +130,17 @@ class ChatJoinRequest(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatJoinRequest"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatJoinRequest":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["chat"] = Chat.de_json(data.get("chat"), bot)
|
||||
data["from_user"] = User.de_json(data.pop("from", None), bot)
|
||||
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
|
||||
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
|
||||
data["date"] = from_timestamp(data.get("date", None), tzinfo=loc_tzinfo)
|
||||
data["invite_link"] = ChatInviteLink.de_json(data.get("invite_link"), bot)
|
||||
data["invite_link"] = de_json_optional(data.get("invite_link"), ChatInviteLink, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -23,6 +23,7 @@ from typing import TYPE_CHECKING, Final, Optional
|
||||
from telegram import constants
|
||||
from telegram._files.location import Location
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -68,16 +69,11 @@ class ChatLocation(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatLocation"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatLocation":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["location"] = Location.de_json(data.get("location"), bot)
|
||||
data["location"] = de_json_optional(data.get("location"), Location, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
+14
-17
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -18,12 +18,14 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram ChatMember."""
|
||||
|
||||
import datetime
|
||||
import datetime as dtm
|
||||
from typing import TYPE_CHECKING, Final, Optional
|
||||
|
||||
from telegram import constants
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils import enum
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
@@ -98,22 +100,17 @@ class ChatMember(TelegramObject):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Required by all subclasses
|
||||
self.user: User = user
|
||||
self.status: str = status
|
||||
self.status: str = enum.get_member(constants.ChatMemberStatus, status, status)
|
||||
|
||||
self._id_attrs = (self.user, self.status)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatMember"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatMember":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
_class_mapping: dict[str, type[ChatMember]] = {
|
||||
cls.OWNER: ChatMemberOwner,
|
||||
cls.ADMINISTRATOR: ChatMemberAdministrator,
|
||||
@@ -126,12 +123,12 @@ class ChatMember(TelegramObject):
|
||||
if cls is ChatMember and data.get("status") in _class_mapping:
|
||||
return _class_mapping[data.pop("status")].de_json(data=data, bot=bot)
|
||||
|
||||
data["user"] = User.de_json(data.get("user"), bot)
|
||||
data["user"] = de_json_optional(data.get("user"), User, bot)
|
||||
if "until_date" in data:
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["until_date"] = from_timestamp(data["until_date"], tzinfo=loc_tzinfo)
|
||||
data["until_date"] = from_timestamp(data.get("until_date"), tzinfo=loc_tzinfo)
|
||||
|
||||
# This is a deprecated field that TG still returns for backwards compatibility
|
||||
# Let's filter it out to speed up the de-json process
|
||||
@@ -413,13 +410,13 @@ class ChatMemberMember(ChatMember):
|
||||
def __init__(
|
||||
self,
|
||||
user: User,
|
||||
until_date: Optional[datetime.datetime] = None,
|
||||
until_date: Optional[dtm.datetime] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(status=ChatMember.MEMBER, user=user, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.until_date: Optional[datetime.datetime] = until_date
|
||||
self.until_date: Optional[dtm.datetime] = until_date
|
||||
|
||||
|
||||
class ChatMemberRestricted(ChatMember):
|
||||
@@ -566,7 +563,7 @@ class ChatMemberRestricted(ChatMember):
|
||||
can_send_other_messages: bool,
|
||||
can_add_web_page_previews: bool,
|
||||
can_manage_topics: bool,
|
||||
until_date: datetime.datetime,
|
||||
until_date: dtm.datetime,
|
||||
can_send_audios: bool,
|
||||
can_send_documents: bool,
|
||||
can_send_photos: bool,
|
||||
@@ -587,7 +584,7 @@ class ChatMemberRestricted(ChatMember):
|
||||
self.can_send_other_messages: bool = can_send_other_messages
|
||||
self.can_add_web_page_previews: bool = can_add_web_page_previews
|
||||
self.can_manage_topics: bool = can_manage_topics
|
||||
self.until_date: datetime.datetime = until_date
|
||||
self.until_date: dtm.datetime = until_date
|
||||
self.can_send_audios: bool = can_send_audios
|
||||
self.can_send_documents: bool = can_send_documents
|
||||
self.can_send_photos: bool = can_send_photos
|
||||
@@ -656,10 +653,10 @@ class ChatMemberBanned(ChatMember):
|
||||
def __init__(
|
||||
self,
|
||||
user: User,
|
||||
until_date: datetime.datetime,
|
||||
until_date: dtm.datetime,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(status=ChatMember.BANNED, user=user, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.until_date: datetime.datetime = until_date
|
||||
self.until_date: dtm.datetime = until_date
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -17,7 +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/].
|
||||
"""This module contains an object that represents a Telegram ChatMemberUpdated."""
|
||||
import datetime
|
||||
import datetime as dtm
|
||||
from typing import TYPE_CHECKING, Optional, Union
|
||||
|
||||
from telegram._chat import Chat
|
||||
@@ -25,6 +25,7 @@ from telegram._chatinvitelink import ChatInviteLink
|
||||
from telegram._chatmember import ChatMember
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
@@ -108,7 +109,7 @@ class ChatMemberUpdated(TelegramObject):
|
||||
self,
|
||||
chat: Chat,
|
||||
from_user: User,
|
||||
date: datetime.datetime,
|
||||
date: dtm.datetime,
|
||||
old_chat_member: ChatMember,
|
||||
new_chat_member: ChatMember,
|
||||
invite_link: Optional[ChatInviteLink] = None,
|
||||
@@ -121,7 +122,7 @@ class ChatMemberUpdated(TelegramObject):
|
||||
# Required
|
||||
self.chat: Chat = chat
|
||||
self.from_user: User = from_user
|
||||
self.date: datetime.datetime = date
|
||||
self.date: dtm.datetime = date
|
||||
self.old_chat_member: ChatMember = old_chat_member
|
||||
self.new_chat_member: ChatMember = new_chat_member
|
||||
self.via_chat_folder_invite_link: Optional[bool] = via_chat_folder_invite_link
|
||||
@@ -141,24 +142,19 @@ class ChatMemberUpdated(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatMemberUpdated"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatMemberUpdated":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["chat"] = Chat.de_json(data.get("chat"), bot)
|
||||
data["from_user"] = User.de_json(data.pop("from", None), bot)
|
||||
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
|
||||
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
|
||||
data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
|
||||
data["old_chat_member"] = ChatMember.de_json(data.get("old_chat_member"), bot)
|
||||
data["new_chat_member"] = ChatMember.de_json(data.get("new_chat_member"), bot)
|
||||
data["invite_link"] = ChatInviteLink.de_json(data.get("invite_link"), bot)
|
||||
data["old_chat_member"] = de_json_optional(data.get("old_chat_member"), ChatMember, bot)
|
||||
data["new_chat_member"] = de_json_optional(data.get("new_chat_member"), ChatMember, bot)
|
||||
data["invite_link"] = de_json_optional(data.get("invite_link"), ChatInviteLink, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -179,9 +175,7 @@ class ChatMemberUpdated(TelegramObject):
|
||||
self,
|
||||
) -> dict[
|
||||
str,
|
||||
tuple[
|
||||
Union[str, bool, datetime.datetime, User], Union[str, bool, datetime.datetime, User]
|
||||
],
|
||||
tuple[Union[str, bool, dtm.datetime, User], Union[str, bool, dtm.datetime, User]],
|
||||
]:
|
||||
"""Computes the difference between :attr:`old_chat_member` and :attr:`new_chat_member`.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -231,15 +231,10 @@ class ChatPermissions(TelegramObject):
|
||||
return cls(*(14 * (False,)))
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChatPermissions"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatPermissions":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
api_kwargs = {}
|
||||
# This is a deprecated field that TG still returns for backwards compatibility
|
||||
# Let's filter it out to speed up the de-json process
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# pylint: disable=too-many-arguments
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -24,6 +24,7 @@ from typing import TYPE_CHECKING, Optional
|
||||
from telegram._files.location import Location
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -92,18 +93,13 @@ class ChosenInlineResult(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["ChosenInlineResult"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChosenInlineResult":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Required
|
||||
data["from_user"] = User.de_json(data.pop("from", None), bot)
|
||||
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
|
||||
# Optionals
|
||||
data["location"] = Location.de_json(data.get("location"), bot)
|
||||
data["location"] = de_json_optional(data.get("location"), Location, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -21,6 +21,7 @@ from typing import TYPE_CHECKING, Optional, TypeVar
|
||||
|
||||
from telegram._files._basemedium import _BaseMedium
|
||||
from telegram._files.photosize import PhotoSize
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -82,17 +83,14 @@ class _BaseThumbedMedium(_BaseMedium):
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls: type[ThumbedMT_co], data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional[ThumbedMT_co]:
|
||||
cls: type[ThumbedMT_co], data: JSONDict, bot: Optional["Bot"] = None
|
||||
) -> ThumbedMT_co:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# In case this wasn't already done by the subclass
|
||||
if not isinstance(data.get("thumbnail"), PhotoSize):
|
||||
data["thumbnail"] = PhotoSize.de_json(data.get("thumbnail"), bot)
|
||||
data["thumbnail"] = de_json_optional(data.get("thumbnail"), PhotoSize, bot)
|
||||
|
||||
api_kwargs = {}
|
||||
# This is a deprecated field that TG still returns for backwards compatibility
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -214,6 +214,13 @@ class InputPaidMediaVideo(InputPaidMedia):
|
||||
Lastly you can pass an existing :class:`telegram.Video` object to send.
|
||||
thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
|
||||
optional): |thumbdocstringnopath|
|
||||
cover (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
|
||||
optional): Cover for the video in the message. |fileinputnopath|
|
||||
|
||||
.. versionchanged:: 21.11
|
||||
start_timestamp (:obj:`int`, optional): Start timestamp for the video in the message
|
||||
|
||||
.. versionchanged:: 21.11
|
||||
width (:obj:`int`, optional): Video width.
|
||||
height (:obj:`int`, optional): Video height.
|
||||
duration (:obj:`int`, optional): Video duration in seconds.
|
||||
@@ -225,6 +232,13 @@ class InputPaidMediaVideo(InputPaidMedia):
|
||||
:tg-const:`telegram.constants.InputPaidMediaType.VIDEO`.
|
||||
media (:obj:`str` | :class:`telegram.InputFile`): Video to send.
|
||||
thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
|
||||
cover (:class:`telegram.InputFile`): Optional. Cover for the video in the message.
|
||||
|fileinputnopath|
|
||||
|
||||
.. versionchanged:: 21.11
|
||||
start_timestamp (:obj:`int`): Optional. Start timestamp for the video in the message
|
||||
|
||||
.. versionchanged:: 21.11
|
||||
width (:obj:`int`): Optional. Video width.
|
||||
height (:obj:`int`): Optional. Video height.
|
||||
duration (:obj:`int`): Optional. Video duration in seconds.
|
||||
@@ -232,7 +246,15 @@ class InputPaidMediaVideo(InputPaidMedia):
|
||||
suitable for streaming.
|
||||
"""
|
||||
|
||||
__slots__ = ("duration", "height", "supports_streaming", "thumbnail", "width")
|
||||
__slots__ = (
|
||||
"cover",
|
||||
"duration",
|
||||
"height",
|
||||
"start_timestamp",
|
||||
"supports_streaming",
|
||||
"thumbnail",
|
||||
"width",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -242,6 +264,8 @@ class InputPaidMediaVideo(InputPaidMedia):
|
||||
height: Optional[int] = None,
|
||||
duration: Optional[int] = None,
|
||||
supports_streaming: Optional[bool] = None,
|
||||
cover: Optional[FileInput] = None,
|
||||
start_timestamp: Optional[int] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -264,6 +288,10 @@ class InputPaidMediaVideo(InputPaidMedia):
|
||||
self.height: Optional[int] = height
|
||||
self.duration: Optional[int] = duration
|
||||
self.supports_streaming: Optional[bool] = supports_streaming
|
||||
self.cover: Optional[Union[InputFile, str]] = (
|
||||
parse_file_input(cover, attach=True, local_mode=True) if cover else None
|
||||
)
|
||||
self.start_timestamp: Optional[int] = start_timestamp
|
||||
|
||||
|
||||
class InputMediaAnimation(InputMedia):
|
||||
@@ -536,6 +564,13 @@ class InputMediaVideo(InputMedia):
|
||||
optional): |thumbdocstringnopath|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
cover (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
|
||||
optional): Cover for the video in the message. |fileinputnopath|
|
||||
|
||||
.. versionchanged:: 21.11
|
||||
start_timestamp (:obj:`int`, optional): Start timestamp for the video in the message
|
||||
|
||||
.. versionchanged:: 21.11
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
@@ -568,13 +603,22 @@ class InputMediaVideo(InputMedia):
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
cover (:class:`telegram.InputFile`): Optional. Cover for the video in the message.
|
||||
|fileinputnopath|
|
||||
|
||||
.. versionchanged:: 21.11
|
||||
start_timestamp (:obj:`int`): Optional. Start timestamp for the video in the message
|
||||
|
||||
.. versionchanged:: 21.11
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"cover",
|
||||
"duration",
|
||||
"has_spoiler",
|
||||
"height",
|
||||
"show_caption_above_media",
|
||||
"start_timestamp",
|
||||
"supports_streaming",
|
||||
"thumbnail",
|
||||
"width",
|
||||
@@ -594,6 +638,8 @@ class InputMediaVideo(InputMedia):
|
||||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
cover: Optional[FileInput] = None,
|
||||
start_timestamp: Optional[int] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -625,6 +671,10 @@ class InputMediaVideo(InputMedia):
|
||||
self.supports_streaming: Optional[bool] = supports_streaming
|
||||
self.has_spoiler: Optional[bool] = has_spoiler
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
self.cover: Optional[Union[InputFile, str]] = (
|
||||
parse_file_input(cover, attach=True, local_mode=True) if cover else None
|
||||
)
|
||||
self.start_timestamp: Optional[int] = start_timestamp
|
||||
|
||||
|
||||
class InputMediaAudio(InputMedia):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -61,8 +61,8 @@ class InputSticker(TelegramObject):
|
||||
format (:obj:`str`): Format of the added sticker, must be one of
|
||||
:tg-const:`telegram.constants.StickerFormat.STATIC` for a
|
||||
``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED`
|
||||
for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a WEBM
|
||||
video.
|
||||
for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a
|
||||
``.WEBM`` video.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
@@ -84,8 +84,8 @@ class InputSticker(TelegramObject):
|
||||
format (:obj:`str`): Format of the added sticker, must be one of
|
||||
:tg-const:`telegram.constants.StickerFormat.STATIC` for a
|
||||
``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED`
|
||||
for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a WEBM
|
||||
video.
|
||||
for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a
|
||||
``.WEBM`` video.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
+10
-16
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -26,7 +26,7 @@ from telegram._files.file import File
|
||||
from telegram._files.photosize import PhotoSize
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils import enum
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -194,16 +194,13 @@ class Sticker(_BaseThumbedMedium):
|
||||
""":const:`telegram.constants.StickerType.CUSTOM_EMOJI`"""
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Sticker"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "Sticker":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["thumbnail"] = PhotoSize.de_json(data.get("thumbnail"), bot)
|
||||
data["mask_position"] = MaskPosition.de_json(data.get("mask_position"), bot)
|
||||
data["premium_animation"] = File.de_json(data.get("premium_animation"), bot)
|
||||
data["thumbnail"] = de_json_optional(data.get("thumbnail"), PhotoSize, bot)
|
||||
data["mask_position"] = de_json_optional(data.get("mask_position"), MaskPosition, bot)
|
||||
data["premium_animation"] = de_json_optional(data.get("premium_animation"), File, bot)
|
||||
|
||||
api_kwargs = {}
|
||||
# This is a deprecated field that TG still returns for backwards compatibility
|
||||
@@ -306,15 +303,12 @@ class StickerSet(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["StickerSet"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "StickerSet":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
if not data:
|
||||
return None
|
||||
data = cls._parse_data(data)
|
||||
|
||||
data["thumbnail"] = PhotoSize.de_json(data.get("thumbnail"), bot)
|
||||
data["stickers"] = Sticker.de_list(data.get("stickers"), bot)
|
||||
data["thumbnail"] = de_json_optional(data.get("thumbnail"), PhotoSize, bot)
|
||||
data["stickers"] = de_list_optional(data.get("stickers"), Sticker, bot)
|
||||
|
||||
api_kwargs = {}
|
||||
# These are deprecated fields that TG still returns for backwards compatibility
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -22,6 +22,7 @@ from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._files.location import Location
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -103,13 +104,10 @@ class Venue(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Venue"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "Venue":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["location"] = Location.de_json(data.get("location"), bot)
|
||||
data["location"] = de_json_optional(data.get("location"), Location, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -17,12 +17,17 @@
|
||||
# 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 Video."""
|
||||
from typing import Optional
|
||||
from collections.abc import Sequence
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._files._basethumbedmedium import _BaseThumbedMedium
|
||||
from telegram._files.photosize import PhotoSize
|
||||
from telegram._utils.argumentparsing import de_list_optional, parse_sequence_arg
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class Video(_BaseThumbedMedium):
|
||||
"""This object represents a video file.
|
||||
@@ -48,6 +53,13 @@ class Video(_BaseThumbedMedium):
|
||||
thumbnail (:class:`telegram.PhotoSize`, optional): Video thumbnail.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
cover (Sequence[:class:`telegram.PhotoSize`], optional): Available sizes of the cover of
|
||||
the video in the message.
|
||||
|
||||
.. versionadded:: 21.11
|
||||
start_timestamp (:obj:`int`, optional): Timestamp in seconds from which the video
|
||||
will play in the message
|
||||
.. versionadded:: 21.11
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
@@ -64,9 +76,24 @@ class Video(_BaseThumbedMedium):
|
||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Video thumbnail.
|
||||
|
||||
.. versionadded:: 20.2
|
||||
cover (tuple[:class:`telegram.PhotoSize`]): Optional, Available sizes of the cover of
|
||||
the video in the message.
|
||||
|
||||
.. versionadded:: 21.11
|
||||
start_timestamp (:obj:`int`): Optional, Timestamp in seconds from which the video
|
||||
will play in the message
|
||||
.. versionadded:: 21.11
|
||||
"""
|
||||
|
||||
__slots__ = ("duration", "file_name", "height", "mime_type", "width")
|
||||
__slots__ = (
|
||||
"cover",
|
||||
"duration",
|
||||
"file_name",
|
||||
"height",
|
||||
"mime_type",
|
||||
"start_timestamp",
|
||||
"width",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -79,6 +106,8 @@ class Video(_BaseThumbedMedium):
|
||||
file_size: Optional[int] = None,
|
||||
file_name: Optional[str] = None,
|
||||
thumbnail: Optional[PhotoSize] = None,
|
||||
cover: Optional[Sequence[PhotoSize]] = None,
|
||||
start_timestamp: Optional[int] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -97,3 +126,14 @@ class Video(_BaseThumbedMedium):
|
||||
# Optional
|
||||
self.mime_type: Optional[str] = mime_type
|
||||
self.file_name: Optional[str] = file_name
|
||||
self.cover: Optional[Sequence[PhotoSize]] = parse_sequence_arg(cover)
|
||||
self.start_timestamp: Optional[int] = start_timestamp
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "Video":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
data["cover"] = de_list_optional(data.get("cover"), PhotoSize, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -24,7 +24,7 @@ from telegram._files.animation import Animation
|
||||
from telegram._files.photosize import PhotoSize
|
||||
from telegram._messageentity import MessageEntity
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
|
||||
from telegram._utils.strings import TextEncoding
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
@@ -124,16 +124,13 @@ class Game(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Game"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "Game":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["photo"] = PhotoSize.de_list(data.get("photo"), bot)
|
||||
data["text_entities"] = MessageEntity.de_list(data.get("text_entities"), bot)
|
||||
data["animation"] = Animation.de_json(data.get("animation"), bot)
|
||||
data["photo"] = de_list_optional(data.get("photo"), PhotoSize, bot)
|
||||
data["text_entities"] = de_list_optional(data.get("text_entities"), MessageEntity, bot)
|
||||
data["animation"] = de_json_optional(data.get("animation"), Animation, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -22,6 +22,7 @@ from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -61,15 +62,10 @@ class GameHighScore(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["GameHighScore"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "GameHighScore":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["user"] = User.de_json(data.get("user"), bot)
|
||||
data["user"] = de_json_optional(data.get("user"), User, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
+26
-15
@@ -2,7 +2,7 @@
|
||||
# pylint: disable=redefined-builtin
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -23,7 +23,7 @@ from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._files.sticker import Sticker
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -46,6 +46,10 @@ class Gift(TelegramObject):
|
||||
sent; for limited gifts only
|
||||
remaining_count (:obj:`int`, optional): The number of remaining gifts of this type that can
|
||||
be sent; for limited gifts only
|
||||
upgrade_star_count (:obj:`int`, optional): The number of Telegram Stars that must be paid
|
||||
to upgrade the gift to a unique one
|
||||
|
||||
.. versionadded:: 21.10
|
||||
|
||||
Attributes:
|
||||
id (:obj:`str`): Unique identifier of the gift
|
||||
@@ -55,10 +59,21 @@ class Gift(TelegramObject):
|
||||
sent; for limited gifts only
|
||||
remaining_count (:obj:`int`): Optional. The number of remaining gifts of this type that can
|
||||
be sent; for limited gifts only
|
||||
upgrade_star_count (:obj:`int`): Optional. The number of Telegram Stars that must be paid
|
||||
to upgrade the gift to a unique one
|
||||
|
||||
.. versionadded:: 21.10
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("id", "remaining_count", "star_count", "sticker", "total_count")
|
||||
__slots__ = (
|
||||
"id",
|
||||
"remaining_count",
|
||||
"star_count",
|
||||
"sticker",
|
||||
"total_count",
|
||||
"upgrade_star_count",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -67,6 +82,7 @@ class Gift(TelegramObject):
|
||||
star_count: int,
|
||||
total_count: Optional[int] = None,
|
||||
remaining_count: Optional[int] = None,
|
||||
upgrade_star_count: Optional[int] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -76,21 +92,19 @@ class Gift(TelegramObject):
|
||||
self.star_count: int = star_count
|
||||
self.total_count: Optional[int] = total_count
|
||||
self.remaining_count: Optional[int] = remaining_count
|
||||
self.upgrade_star_count: Optional[int] = upgrade_star_count
|
||||
|
||||
self._id_attrs = (self.id,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Gift"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "Gift":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["sticker"] = Sticker.de_json(data.get("sticker"), bot)
|
||||
return cls(**data)
|
||||
data["sticker"] = de_json_optional(data.get("sticker"), Sticker, bot)
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class Gifts(TelegramObject):
|
||||
@@ -125,12 +139,9 @@ class Gifts(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Gifts"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "Gifts":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["gifts"] = Gift.de_list(data.get("gifts"), bot)
|
||||
return cls(**data)
|
||||
data["gifts"] = de_list_optional(data.get("gifts"), Gift, bot)
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
+14
-29
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -17,14 +17,14 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an objects that are related to Telegram giveaways."""
|
||||
import datetime
|
||||
import datetime as dtm
|
||||
from collections.abc import Sequence
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._chat import Chat
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
@@ -105,7 +105,7 @@ class Giveaway(TelegramObject):
|
||||
def __init__(
|
||||
self,
|
||||
chats: Sequence[Chat],
|
||||
winners_selection_date: datetime.datetime,
|
||||
winners_selection_date: dtm.datetime,
|
||||
winner_count: int,
|
||||
only_new_members: Optional[bool] = None,
|
||||
has_public_winners: Optional[bool] = None,
|
||||
@@ -119,7 +119,7 @@ class Giveaway(TelegramObject):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
self.chats: tuple[Chat, ...] = tuple(chats)
|
||||
self.winners_selection_date: datetime.datetime = winners_selection_date
|
||||
self.winners_selection_date: dtm.datetime = winners_selection_date
|
||||
self.winner_count: int = winner_count
|
||||
self.only_new_members: Optional[bool] = only_new_members
|
||||
self.has_public_winners: Optional[bool] = has_public_winners
|
||||
@@ -137,19 +137,14 @@ class Giveaway(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["Giveaway"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "Giveaway":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if data is None:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["chats"] = tuple(Chat.de_list(data.get("chats"), bot))
|
||||
data["chats"] = de_list_optional(data.get("chats"), Chat, bot)
|
||||
data["winners_selection_date"] = from_timestamp(
|
||||
data.get("winners_selection_date"), tzinfo=loc_tzinfo
|
||||
)
|
||||
@@ -260,7 +255,7 @@ class GiveawayWinners(TelegramObject):
|
||||
self,
|
||||
chat: Chat,
|
||||
giveaway_message_id: int,
|
||||
winners_selection_date: datetime.datetime,
|
||||
winners_selection_date: dtm.datetime,
|
||||
winner_count: int,
|
||||
winners: Sequence[User],
|
||||
additional_chat_count: Optional[int] = None,
|
||||
@@ -277,7 +272,7 @@ class GiveawayWinners(TelegramObject):
|
||||
|
||||
self.chat: Chat = chat
|
||||
self.giveaway_message_id: int = giveaway_message_id
|
||||
self.winners_selection_date: datetime.datetime = winners_selection_date
|
||||
self.winners_selection_date: dtm.datetime = winners_selection_date
|
||||
self.winner_count: int = winner_count
|
||||
self.winners: tuple[User, ...] = tuple(winners)
|
||||
self.additional_chat_count: Optional[int] = additional_chat_count
|
||||
@@ -299,20 +294,15 @@ class GiveawayWinners(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["GiveawayWinners"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "GiveawayWinners":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if data is None:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["chat"] = Chat.de_json(data.get("chat"), bot)
|
||||
data["winners"] = tuple(User.de_list(data.get("winners"), bot))
|
||||
data["chat"] = de_json_optional(data.get("chat"), Chat, bot)
|
||||
data["winners"] = de_list_optional(data.get("winners"), User, bot)
|
||||
data["winners_selection_date"] = from_timestamp(
|
||||
data.get("winners_selection_date"), tzinfo=loc_tzinfo
|
||||
)
|
||||
@@ -376,18 +366,13 @@ class GiveawayCompleted(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["GiveawayCompleted"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "GiveawayCompleted":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if data is None:
|
||||
return None
|
||||
|
||||
# Unfortunately, this needs to be here due to cyclic imports
|
||||
from telegram._message import Message # pylint: disable=import-outside-toplevel
|
||||
|
||||
data["giveaway_message"] = Message.de_json(data.get("giveaway_message"), bot)
|
||||
data["giveaway_message"] = de_json_optional(data.get("giveaway_message"), Message, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -26,6 +26,7 @@ from telegram._games.callbackgame import CallbackGame
|
||||
from telegram._loginurl import LoginUrl
|
||||
from telegram._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._webappinfo import WebAppInfo
|
||||
|
||||
@@ -296,22 +297,17 @@ class InlineKeyboardButton(TelegramObject):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["InlineKeyboardButton"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "InlineKeyboardButton":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["login_url"] = LoginUrl.de_json(data.get("login_url"), bot)
|
||||
data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot)
|
||||
data["callback_game"] = CallbackGame.de_json(data.get("callback_game"), bot)
|
||||
data["switch_inline_query_chosen_chat"] = SwitchInlineQueryChosenChat.de_json(
|
||||
data.get("switch_inline_query_chosen_chat"), bot
|
||||
data["login_url"] = de_json_optional(data.get("login_url"), LoginUrl, bot)
|
||||
data["web_app"] = de_json_optional(data.get("web_app"), WebAppInfo, bot)
|
||||
data["callback_game"] = de_json_optional(data.get("callback_game"), CallbackGame, bot)
|
||||
data["switch_inline_query_chosen_chat"] = de_json_optional(
|
||||
data.get("switch_inline_query_chosen_chat"), SwitchInlineQueryChosenChat, bot
|
||||
)
|
||||
data["copy_text"] = CopyTextButton.de_json(data.get("copy_text"), bot)
|
||||
data["copy_text"] = de_json_optional(data.get("copy_text"), CopyTextButton, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -91,12 +91,8 @@ class InlineKeyboardMarkup(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["InlineKeyboardMarkup"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "InlineKeyboardMarkup":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
keyboard = []
|
||||
for row in data["inline_keyboard"]:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# pylint: disable=too-many-arguments
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -27,8 +27,9 @@ from telegram._files.location import Location
|
||||
from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import de_json_optional
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import JSONDict, ODVInput
|
||||
from telegram._utils.types import JSONDict, ODVInput, TimePeriod
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, InlineQueryResult
|
||||
@@ -126,17 +127,12 @@ class InlineQuery(TelegramObject):
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["InlineQuery"]:
|
||||
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "InlineQuery":
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["from_user"] = User.de_json(data.pop("from", None), bot)
|
||||
data["location"] = Location.de_json(data.get("location"), bot)
|
||||
data["from_user"] = de_json_optional(data.pop("from", None), User, bot)
|
||||
data["location"] = de_json_optional(data.get("location"), Location, bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -145,7 +141,7 @@ class InlineQuery(TelegramObject):
|
||||
results: Union[
|
||||
Sequence["InlineQueryResult"], Callable[[int], Optional[Sequence["InlineQueryResult"]]]
|
||||
],
|
||||
cache_time: Optional[int] = None,
|
||||
cache_time: Optional[TimePeriod] = None,
|
||||
is_personal: Optional[bool] = None,
|
||||
next_offset: Optional[str] = None,
|
||||
button: Optional[InlineQueryResultsButton] = None,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -38,6 +38,9 @@ class InlineQueryResultArticle(InlineQueryResult):
|
||||
.. versionchanged:: 20.5
|
||||
Removed the deprecated arguments and attributes ``thumb_*``.
|
||||
|
||||
.. versionchanged:: 21.11
|
||||
Removed the deprecated argument and attribute ``hide_url``.
|
||||
|
||||
Args:
|
||||
id (:obj:`str`): Unique identifier for this result,
|
||||
:tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
|
||||
@@ -48,8 +51,9 @@ class InlineQueryResultArticle(InlineQueryResult):
|
||||
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
|
||||
to the message.
|
||||
url (:obj:`str`, optional): URL of the result.
|
||||
hide_url (:obj:`bool`, optional): Pass :obj:`True`, if you don't want the URL to be shown
|
||||
in the message.
|
||||
|
||||
Tip:
|
||||
Pass an empty string as URL if you don't want the URL to be shown in the message.
|
||||
description (:obj:`str`, optional): Short description of the result.
|
||||
thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result.
|
||||
|
||||
@@ -72,8 +76,6 @@ class InlineQueryResultArticle(InlineQueryResult):
|
||||
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
|
||||
to the message.
|
||||
url (:obj:`str`): Optional. URL of the result.
|
||||
hide_url (:obj:`bool`): Optional. Pass :obj:`True`, if you don't want the URL to be shown
|
||||
in the message.
|
||||
description (:obj:`str`): Optional. Short description of the result.
|
||||
thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result.
|
||||
|
||||
@@ -89,7 +91,6 @@ class InlineQueryResultArticle(InlineQueryResult):
|
||||
|
||||
__slots__ = (
|
||||
"description",
|
||||
"hide_url",
|
||||
"input_message_content",
|
||||
"reply_markup",
|
||||
"thumbnail_height",
|
||||
@@ -106,7 +107,6 @@ class InlineQueryResultArticle(InlineQueryResult):
|
||||
input_message_content: "InputMessageContent",
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
url: Optional[str] = None,
|
||||
hide_url: Optional[bool] = None,
|
||||
description: Optional[str] = None,
|
||||
thumbnail_url: Optional[str] = None,
|
||||
thumbnail_width: Optional[int] = None,
|
||||
@@ -123,7 +123,6 @@ class InlineQueryResultArticle(InlineQueryResult):
|
||||
# Optional
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.url: Optional[str] = url
|
||||
self.hide_url: Optional[bool] = hide_url
|
||||
self.description: Optional[str] = description
|
||||
self.thumbnail_url: Optional[str] = thumbnail_url
|
||||
self.thumbnail_width: Optional[int] = thumbnail_width
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Copyright (C) 2015-2025
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user