Compare commits

...

21 Commits

Author SHA1 Message Date
Bibo-Joshi fc3863ac9a Bump Version to v22.1 (#4791) 2025-05-15 22:18:11 +02:00
Bibo-Joshi c57e9fa5d6 Documentation Improvements (#4730)
Co-authored-by: Poolitzer <github@poolitzer.eu>
Co-authored-by: Abdelrahman Elkheir <90580077+aelkheir@users.noreply.github.com>
2025-05-15 21:57:07 +02:00
Bibo-Joshi 7078059e80 Full Support for Bot API 9.0 (#4756)
Co-authored-by: Abdelrahman Elkheir <90580077+aelkheir@users.noreply.github.com>
2025-05-15 21:56:10 +02:00
pre-commit-ci[bot] c34e19edfd Bump pre-commit Hooks to Latest Versions (#4748)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2025-05-12 21:23:25 +02:00
dependabot[bot] 2fc04e1e10 Bump actions/upload-artifact from 4.5.0 to 4.6.2 (#4776)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2025-05-03 21:03:39 +02:00
dependabot[bot] 08006013c3 Bump actions/download-artifact from 4.2.1 to 4.3.0 (#4779)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2025-05-03 20:40:35 +02:00
dependabot[bot] 4c61403322 Bump codecov/codecov-action from 5.1.2 to 5.4.2 (#4775)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2025-05-03 20:40:02 +02:00
dependabot[bot] b0faae9d47 Bump stefanzweifel/git-auto-commit-action from 5.1.0 to 5.2.0 (#4777)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2025-05-03 20:39:19 +02:00
dependabot[bot] 4868565b71 Bump github/codeql-action from 3.28.13 to 3.28.16 (#4778)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2025-05-03 20:38:58 +02:00
Bibo-Joshi 486ceaa6cf Clarify Documentation and Type Hints of Input(Paid)Media (#4762)
Co-authored-by: aelkheir <90580077+aelkheir@users.noreply.github.com>
2025-04-20 10:48:51 +02:00
Bibo-Joshi 54ce1d8d82 Fine Tune chango and Release Workflows (#4758) 2025-04-19 18:40:47 +02:00
ngrogolev 17ae6a7028 Fix Handling of Defaults for InputPaidMedia (#4761)
Co-authored-by: Nikita Grogolev <ngrogolev@leantech.ai>
2025-04-19 17:02:43 +02:00
Bibo-Joshi c6e12b1958 Drop Backward Compatibility for user_id in send_gift (#4692) 2025-04-11 19:16:31 +02:00
Poolitzer ed9496b91a Ensure Proper Execution of Bot.shutdown (#4733) 2025-04-08 19:45:10 +02:00
dependabot[bot] 7823822a41 Bump actions/setup-python from 5.4.0 to 5.5.0 (#4742)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2025-04-07 20:26:31 +02:00
Bibo-Joshi a9e53af3d1 Update AUTHORS.rst, Adding @aelkheir to Active Development Team (#4747) 2025-04-07 19:55:31 +02:00
dependabot[bot] e69069d2c8 Bump github/codeql-action from 3.28.10 to 3.28.13 (#4743)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2025-04-06 20:32:46 +02:00
dependabot[bot] 511222c191 Bump codecov/test-results-action from 1.0.2 to 1.1.0 (#4741)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2025-04-06 20:25:39 +02:00
dependabot[bot] 036910ec0c Bump astral-sh/setup-uv from 5.3.1 to 5.4.1 (#4744)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2025-04-06 20:25:13 +02:00
dependabot[bot] 3cd8a409ee Bump actions/download-artifact from 4.1.8 to 4.2.1 (#4745)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2025-04-06 20:10:00 +02:00
Abdelrahman Elkheir 83676dec16 Reenable test_official Blocked by Debug Remnant (#4746)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2025-04-06 20:04:00 +02:00
147 changed files with 8532 additions and 333 deletions
+31 -29
View File
@@ -157,45 +157,47 @@ Check-list for PRs
This checklist is a non-exhaustive reminder of things that should be done before a PR is merged, both for you as contributor and for the maintainers.
Feel free to copy (parts of) the checklist to the PR description to remind you or the maintainers of open points or if you have questions on anything.
- Added ``.. versionadded:: NEXT.VERSION``, ``.. versionchanged:: NEXT.VERSION``, ``.. deprecated:: NEXT.VERSION`` or ``.. versionremoved:: NEXT.VERSION`` to the docstrings for user facing changes (for methods/class descriptions, arguments and attributes)
- Created new or adapted existing unit tests
- Documented code changes according to the `CSI standard <https://standards.mousepawmedia.com/en/stable/csi.html>`__
- Added myself alphabetically to ``AUTHORS.rst`` (optional)
- Added new classes & modules to the docs and all suitable ``__all__`` s
- Checked the `Stability Policy <https://docs.python-telegram-bot.org/stability_policy.html>`_ in case of deprecations or changes to documented behavior
.. code-block:: markdown
**If the PR contains API changes (otherwise, you can ignore this passage)**
## Check-list for PRs
- Checked the Bot API specific sections of the `Stability Policy <https://docs.python-telegram-bot.org/stability_policy.html>`_
- Created a PR to remove functionality deprecated in the previous Bot API release (`see here <https://docs.python-telegram-bot.org/en/stable/stability_policy.html#case-2>`_)
- [ ] Added `.. versionadded:: NEXT.VERSION`, ``.. versionchanged:: NEXT.VERSION``, ``.. deprecated:: NEXT.VERSION`` or ``.. versionremoved:: NEXT.VERSION` to the docstrings for user facing changes (for methods/class descriptions, arguments and attributes)
- [ ] Created new or adapted existing unit tests
- [ ] Documented code changes according to the [CSI standard](https://standards.mousepawmedia.com/en/stable/csi.html)
- [ ] Added myself alphabetically to `AUTHORS.rst` (optional)
- [ ] Added new classes & modules to the docs and all suitable ``__all__`` s
- [ ] Checked the [Stability Policy](https://docs.python-telegram-bot.org/stability_policy.html) in case of deprecations or changes to documented behavior
- New classes:
**If the PR contains API changes (otherwise, you can ignore this passage)**
- Added ``self._id_attrs`` and corresponding documentation
- ``__init__`` accepts ``api_kwargs`` as kw-only
- [ ] Checked the Bot API specific sections of the [Stability Policy](https://docs.python-telegram-bot.org/stability_policy.html)
- [ ] Created a PR to remove functionality deprecated in the previous Bot API release ([see here](https://docs.python-telegram-bot.org/en/stable/stability_policy.html#case-2))
- Added new shortcuts:
- New Classes
- In :class:`~telegram.Chat` & :class:`~telegram.User` for all methods that accept ``chat/user_id``
- In :class:`~telegram.Message` for all methods that accept ``chat_id`` and ``message_id``
- For new :class:`~telegram.Message` shortcuts: Added ``quote`` argument if methods accepts ``reply_to_message_id``
- In :class:`~telegram.CallbackQuery` for all methods that accept either ``chat_id`` and ``message_id`` or ``inline_message_id``
- [ ] Added `self._id_attrs` and corresponding documentation
- [ ] `__init__` accepts `api_kwargs` as keyword-only
- If relevant:
- Added New Shortcuts
- Added new constants at :mod:`telegram.constants` and shortcuts to them as class variables
- Link new and existing constants in docstrings instead of hard-coded numbers and strings
- Add new message types to :attr:`telegram.Message.effective_attachment`
- Added new handlers for new update types
- [ ] In [`telegram.Chat`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.chat.html) \& [`telegram.User`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.user.html) for all methods that accept `chat/user_id`
- [ ] In [`telegram.Message`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.message.html) for all methods that accept `chat_id` and `message_id`
- [ ] For new `telegram.Message` shortcuts: Added `quote` argument if methods accept `reply_to_message_id`
- [ ] In [`telegram.CallbackQuery`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.callbackquery.html) for all methods that accept either `chat_id` and `message_id` or `inline_message_id`
- Add the handlers to the warning loop in the :class:`~telegram.ext.ConversationHandler`
- If Relevant
- Added new filters for new message (sub)types
- Added or updated documentation for the changed class(es) and/or method(s)
- Added the new method(s) to ``_extbot.py``
- Added or updated ``bot_methods.rst``
- Updated the Bot API version number in all places: ``README.rst`` (including the badge) and ``telegram.constants.BOT_API_VERSION_INFO``
- Added logic for arbitrary callback data in :class:`telegram.ext.ExtBot` for new methods that either accept a ``reply_markup`` in some form or have a return type that is/contains :class:`~telegram.Message`
- [ ] Added new constants at `telegram.constants` and shortcuts to them as class variables
- [ ] Linked new and existing constants in docstrings instead of hard-coded numbers and strings
- [ ] Added new message types to `telegram.Message.effective_attachment`
- [ ] Added new handlers for new update types
- [ ] Added the handlers to the warning loop in the [`telegram.ext.ConversationHandler`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.conversationhandler.html)
- [ ] Added new filters for new message (sub)types
- [ ] Added or updated documentation for the changed class(es) and/or method(s)
- [ ] Added the new method(s) to `_extbot.py`
- [ ] Added or updated `bot_methods.rst`
- [ ] Updated the Bot API version number in all places: `README.rst` (including the badge) and `telegram.constants.BOT_API_VERSION_INFO`
- [ ] Added logic for arbitrary callback data in `telegram.ext.ExtBot` for new methods that either accept a `reply_markup` in some form or have a return type that is/contains [`telegram.Message`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.message.html)
Documenting
===========
+66
View File
@@ -0,0 +1,66 @@
name: Chango
on:
pull_request:
types:
- opened
- reopened
- synchronize
permissions: {}
jobs:
create-chango-fragment:
permissions:
# Give the default GITHUB_TOKEN write permission to commit and push the
# added or changed files to the repository.
contents: write
name: Create chango Fragment
runs-on: ubuntu-latest
outputs:
IS_RELEASE_PR: ${{ steps.check_title.outputs.IS_RELEASE_PR }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# needed for commit and push step at the end
persist-credentials: true
- name: Check PR Title
id: check_title
run: | # zizmor: ignore[template-injection]
if [[ "$(echo "${{ github.event.pull_request.title }}" | tr '[:upper:]' '[:lower:]')" =~ ^bump\ version\ to\ .* ]]; then
echo "COMMIT_AND_PUSH=false" >> $GITHUB_OUTPUT
echo "IS_RELEASE_PR=true" >> $GITHUB_OUTPUT
else
echo "COMMIT_AND_PUSH=true" >> $GITHUB_OUTPUT
echo "IS_RELEASE_PR=false" >> $GITHUB_OUTPUT
fi
# Create the new fragment
- uses: Bibo-Joshi/chango@9d6bd9d7612eca5fab2c5161687011be59baaf19 # v0.4.0
with:
github-token: ${{ secrets.CHANGO_PAT }}
query-issue-types: true
commit-and-push: ${{ steps.check_title.outputs.COMMIT_AND_PUSH }}
# Run `chango release` if applicable - needs some additional setup.
- name: Set up Python
if: steps.check_title.outputs.IS_RELEASE_PR == 'true'
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: "3.x"
- name: Do Release
if: steps.check_title.outputs.IS_RELEASE_PR == 'true'
run: |
cd ./target-repo
git add changes/unreleased/*
pip install . -r docs/requirements-docs.txt
VERSION_TAG=$(python -c "from telegram import __version__; print(f'{__version__}')")
chango release --uid $VERSION_TAG
- name: Commit & Push
if: steps.check_title.outputs.IS_RELEASE_PR == 'true'
uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5.2.0
with:
commit_message: "Do chango Release"
repository: ./target-repo
-30
View File
@@ -1,30 +0,0 @@
name: Create Chango Fragment
on:
pull_request:
types:
- opened
- reopened
- synchronize
permissions: {}
jobs:
create-chango-fragment:
permissions:
# Give the default GITHUB_TOKEN write permission to commit and push the
# added or changed files to the repository.
contents: write
name: create-chango-fragment
runs-on: ubuntu-latest
steps:
# Create the new fragment
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: Bibo-Joshi/chango@9d6bd9d7612eca5fab2c5161687011be59baaf19 # v0.4.0
with:
github-token: ${{ secrets.CHANGO_PAT }}
query-issue-types: true
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
+3 -3
View File
@@ -23,7 +23,7 @@ jobs:
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
@@ -31,11 +31,11 @@ jobs:
python -W ignore -m pip install --upgrade pip
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
run: sphinx-build docs/source docs/build/html --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
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: linkcheck-output
path: docs/build/html/output.*
+2 -2
View File
@@ -21,13 +21,13 @@ jobs:
with:
persist-credentials: false
- name: Install the latest version of uv
uses: astral-sh/setup-uv@f94ec6bedd8674c4426838e6b50417d36b6ab231 # v5.3.1
uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1
- 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@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
with:
sarif_file: results.sarif
category: zizmor
+12 -6
View File
@@ -21,7 +21,7 @@ jobs:
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: "3.x"
- name: Install pypa/build
@@ -30,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@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: python-package-distributions
path: dist/
@@ -55,7 +55,7 @@ jobs:
steps:
- name: Download all the dists
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: python-package-distributions
path: dist/
@@ -74,7 +74,7 @@ jobs:
steps:
- name: Download all the dists
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: python-package-distributions
path: dist/
@@ -92,7 +92,7 @@ jobs:
./dist/*.tar.gz
./dist/*.whl
- name: Store the distribution packages and signatures
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: python-package-distributions-and-signatures
path: dist/
@@ -110,8 +110,11 @@ jobs:
actions: read # for downloading artifacts
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Download all the dists
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: python-package-distributions-and-signatures
path: dist/
@@ -150,6 +153,9 @@ jobs:
permissions: {}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Publish to Telegram Channel
env:
TAG: ${{ needs.build.outputs.TAG }}
+9 -6
View File
@@ -21,7 +21,7 @@ jobs:
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: "3.x"
- name: Install pypa/build
@@ -30,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@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: python-package-distributions
path: dist/
@@ -55,7 +55,7 @@ jobs:
steps:
- name: Download all the dists
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: python-package-distributions
path: dist/
@@ -76,7 +76,7 @@ jobs:
steps:
- name: Download all the dists
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: python-package-distributions
path: dist/
@@ -94,7 +94,7 @@ jobs:
./dist/*.tar.gz
./dist/*.whl
- name: Store the distribution packages and signatures
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: python-package-distributions-and-signatures
path: dist/
@@ -112,8 +112,11 @@ jobs:
actions: read # for downloading artifacts
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Download all the dists
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: python-package-distributions-and-signatures
path: dist/
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
+3 -3
View File
@@ -30,7 +30,7 @@ jobs:
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
@@ -92,14 +92,14 @@ jobs:
.test_report_optionals_junit.xml
- name: Submit coverage
uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # v5.1.2
uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.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@4e79e65778be1cecd5df25e14af1eafb6df80ea9 # v1.0.2
uses: codecov/test-results-action@f2dba722c67b86c6caa034178c6e4d35335f6706 # v1.1.0
if: ${{ !cancelled() }}
with:
files: .test_report_no_optionals_junit.xml,.test_report_optionals_junit.xml
+6 -6
View File
@@ -7,7 +7,7 @@ ci:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.8.6'
rev: 'v0.11.9'
hooks:
- id: ruff
name: ruff
@@ -18,18 +18,18 @@ repos:
- cachetools>=5.3.3,<5.5.0
- aiolimiter~=1.1,<1.3
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.10.0
rev: 25.1.0
hooks:
- id: black
args:
- --diff
- --check
- repo: https://github.com/PyCQA/flake8
rev: 7.1.1
rev: 7.2.0
hooks:
- id: flake8
- repo: https://github.com/PyCQA/pylint
rev: v3.3.3
rev: v3.3.6
hooks:
- id: pylint
files: ^(?!(tests|docs)).*\.py$
@@ -41,7 +41,7 @@ repos:
- aiolimiter~=1.1,<1.3
- . # this basically does `pip install -e .`
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.14.1
rev: v1.15.0
hooks:
- id: mypy
name: mypy-ptb
@@ -74,7 +74,7 @@ repos:
args:
- --py39-plus
- repo: https://github.com/pycqa/isort
rev: 5.13.2
rev: 6.0.1
hooks:
- id: isort
name: isort
+4 -4
View File
@@ -7,10 +7,8 @@ The current development team includes
- `Hinrich Mahler <https://github.com/Bibo-Joshi>`_ (maintainer)
- `Poolitzer <https://github.com/Poolitzer>`_ (community liaison)
- `Shivam <https://github.com/Starry69>`_
- `Harshil <https://github.com/harshil21>`_
- `Dmitry Kolomatskiy <https://github.com/lemontree210>`_
- `Aditya <https://github.com/clot27>`_
- `Abdelrahman <https://github.com/aelkheir>`_
Emeritus maintainers include
`Jannes Höke <https://github.com/jh0ker>`_ (`@jh0ker <https://t.me/jh0ker>`_ on Telegram),
@@ -21,7 +19,7 @@ Contributors
The following wonderful people contributed directly or indirectly to this project:
- `Abdelrahman <https://github.com/aelkheir>`_
- `Aditya <https://github.com/clot27>`_
- `Abshar <https://github.com/abxhr>`_
- `Abubakar Alaya <https://github.com/Ecode2>`_
- `Alateas <https://github.com/alateas>`_
@@ -42,6 +40,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `daimajia <https://github.com/daimajia>`_
- `Daniel Reed <https://github.com/nmlorg>`_
- `D David Livingston <https://github.com/daviddl9>`_
- `Dmitry Kolomatskiy <https://github.com/lemontree210>`_
- `DonalDuck004 <https://github.com/DonalDuck004>`_
- `Eana Hufwe <https://github.com/blueset>`_
- `Ehsan Online <https://github.com/ehsanonline>`_
@@ -122,6 +121,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Sam Mosleh <https://github.com/sam-mosleh>`_
- `Sascha <https://github.com/saschalalala>`_
- `Shelomentsev D <https://github.com/shelomentsevd>`_
- `Shivam <https://github.com/Starry69>`_
- `Shivam Saini <https://github.com/shivamsn97>`_
- `Siloé Garcez <https://github.com/roast-lord>`_
- `Simon Schürrle <https://github.com/SitiSchu>`_
+3 -3
View File
@@ -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.3-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-9.0-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API version
@@ -19,7 +19,7 @@
:target: https://pypistats.org/packages/python-telegram-bot
:alt: PyPi Package Monthly Download
.. image:: https://readthedocs.org/projects/python-telegram-bot/badge/?version=stable
.. image:: https://app.readthedocs.org/projects/python-telegram-bot/badge/?version=stable
:target: https://docs.python-telegram-bot.org/en/stable/
:alt: Documentation Status
@@ -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.3** are natively supported by this library.
All types and methods of the Telegram Bot API **9.0** 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
@@ -1,5 +1,5 @@
internal = "Bump github/codeql-action from 3.28.8 to 3.28.10"
[[pull_requests]]
uid = "4697"
author_uid = "dependabot[bot]"
author_uid = "dependabot"
closes_threads = []
@@ -1,5 +1,5 @@
internal = "Bump srvaroa/labeler from 1.12.0 to 1.13.0"
[[pull_requests]]
uid = "4698"
author_uid = "dependabot[bot]"
author_uid = "dependabot"
closes_threads = []
@@ -1,5 +1,5 @@
internal = "Bump astral-sh/setup-uv from 5.2.2 to 5.3.1"
[[pull_requests]]
uid = "4699"
author_uid = "dependabot[bot]"
author_uid = "dependabot"
closes_threads = []
@@ -1,5 +1,5 @@
internal = "Bump Bibo-Joshi/chango from 0.3.1 to 0.3.2"
[[pull_requests]]
uid = "4700"
author_uid = "dependabot[bot]"
author_uid = "dependabot"
closes_threads = []
@@ -1,5 +1,5 @@
internal = "Bump pypa/gh-action-pypi-publish from 1.12.3 to 1.12.4"
[[pull_requests]]
uid = "4701"
author_uid = "dependabot[bot]"
author_uid = "dependabot"
closes_threads = []
@@ -1,5 +1,5 @@
internal = "Bump pytest from 8.3.4 to 8.3.5"
[[pull_requests]]
uid = "4709"
author_uid = "dependabot[bot]"
author_uid = "dependabot"
closes_threads = []
@@ -1,5 +1,5 @@
internal = "Bump sphinx from 8.1.3 to 8.2.3"
[[pull_requests]]
uid = "4710"
author_uid = "dependabot[bot]"
author_uid = "dependabot"
closes_threads = []
@@ -0,0 +1,5 @@
breaking = "Drop backward compatibility for ``user_id`` in ``send_gift`` by updating the order of parameters. Please adapt your code accordingly or use keyword arguments."
[[pull_requests]]
uid = "4692"
author_uid = "Bibo-Joshi"
closes_threads = []
@@ -0,0 +1,9 @@
documentation = "Documentation Improvements. Among others, add missing ``Returns`` field in ``User.get_profile_photos``"
[[pull_requests]]
uid = "4730"
author_uid = "Bibo-Joshi"
closes_threads = []
[[pull_requests]]
uid = "4740"
author_uid = "aelkheir"
closes_threads = []
@@ -0,0 +1,5 @@
bugfixes = "Ensure execution of ``Bot.shutdown()`` even if ``Bot.get_me()`` fails in ``Bot.initialize()``"
[[pull_requests]]
uid = "4733"
author_uid = "Poolitzer"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Bump codecov/test-results-action from 1.0.2 to 1.1.0"
[[pull_requests]]
uid = "4741"
author_uid = "dependabot"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Bump actions/setup-python from 5.4.0 to 5.5.0"
[[pull_requests]]
uid = "4742"
author_uid = "dependabot"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Bump github/codeql-action from 3.28.10 to 3.28.13"
[[pull_requests]]
uid = "4743"
author_uid = "dependabot"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Bump astral-sh/setup-uv from 5.3.1 to 5.4.1"
[[pull_requests]]
uid = "4744"
author_uid = "dependabot"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Bump actions/download-artifact from 4.1.8 to 4.2.1"
[[pull_requests]]
uid = "4745"
author_uid = "dependabot"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Reenable ``test_official`` Blocked by Debug Remnant"
[[pull_requests]]
uid = "4746"
author_uid = "aelkheir"
closes_threads = []
@@ -0,0 +1,5 @@
documentation = "Update ``AUTHORS.rst``, Adding `@aelkheir <https://github.com/aelkheir>`_ to Active Development Team"
[[pull_requests]]
uid = "4747"
author_uid = "Bibo-Joshi"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Bump `pre-commit` Hooks to Latest Versions"
[[pull_requests]]
uid = "4748"
author_uid = "pre-commit-ci"
closes_threads = []
@@ -0,0 +1,51 @@
features = "Full Support for Bot API 9.0"
deprecations = """This release comes with several deprecations, in line with our :ref:`stability policy <stability-policy>`.
This includes the following:
- Deprecated ``telegram.constants.StarTransactionsLimit.NANOSTAR_MIN_AMOUNT`` and ``telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT``. These members will be replaced by ``telegram.constants.NanostarLimit.MIN_AMOUNT`` and ``telegram.constants.NanostarLimit.MAX_AMOUNT``.
- Deprecated the class ``telegram.constants.StarTransactions``. Its only member ``telegram.constants.StarTransactions.NANOSTAR_VALUE`` will be replaced by ``telegram.constants.Nanostar.VALUE``.
- Bot API 9.0 deprecated ``BusinessConnection.can_reply`` in favor of ``BusinessConnection.rights``
- Bot API 9.0 deprecated ``ChatFullInfo.can_send_gift`` in favor of ``ChatFullInfo.accepted_gift_types``.
- Bot API 9.0 introduced these new required fields to existing classes:
- ``TransactionPartnerUser.transaction_type``
- ``ChatFullInfo.accepted_gift_types``
Passing these values as positional arguments is deprecated. We encourage you to use keyword arguments instead, as the the signature will be updated in a future release.
These deprecations are backward compatible, but we strongly recommend to update your code to use the new members.
"""
[[pull_requests]]
uid = "4756"
author_uid = "Bibo-Joshi"
closes_threads = ["4754"]
[[pull_requests]]
uid = "4757"
author_uid = "Bibo-Joshi"
closes_threads = []
[[pull_requests]]
uid = "4759"
author_uid = "Bibo-Joshi"
closes_threads = []
[[pull_requests]]
uid = "4763"
author_uid = "aelkheir"
closes_threads = []
[[pull_requests]]
uid = "4766"
author_uid = "Bibo-Joshi"
[[pull_requests]]
uid = "4769"
author_uid = "aelkheir"
closes_threads = []
[[pull_requests]]
uid = "4773"
author_uid = "aelkheir"
closes_threads = []
[[pull_requests]]
uid = "4781"
author_uid = "aelkheir"
closes_threads = []
[[pull_requests]]
uid = "4782"
author_uid = "Bibo-Joshi"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Fine-tune ``chango`` and release workflows"
[[pull_requests]]
uid = "4758"
author_uid = "Bibo-Joshi"
closes_threads = ["4720"]
@@ -0,0 +1,6 @@
bugfixes = "Fix Handling of ``Defaults`` for ``InputPaidMedia``"
[[pull_requests]]
uid = "4761"
author_uid = "ngrogolev"
closes_threads = ["4753"]
@@ -0,0 +1,5 @@
documentation = "Clarify Documentation and Type Hints of ``InputMedia`` and ``InputPaidMedia``. Note that the ``media`` parameter accepts only objects of type ``str`` and ``InputFile``. The respective subclasses of ``Input(Paid)Media`` each accept a broader range of input type for the ``media`` parameter."
[[pull_requests]]
uid = "4762"
author_uid = "Bibo-Joshi"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Bump codecov/codecov-action from 5.1.2 to 5.4.2"
[[pull_requests]]
uid = "4775"
author_uid = "dependabot"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Bump actions/upload-artifact from 4.5.0 to 4.6.2"
[[pull_requests]]
uid = "4776"
author_uid = "dependabot"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Bump stefanzweifel/git-auto-commit-action from 5.1.0 to 5.2.0"
[[pull_requests]]
uid = "4777"
author_uid = "dependabot"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Bump github/codeql-action from 3.28.13 to 3.28.16"
[[pull_requests]]
uid = "4778"
author_uid = "dependabot"
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Bump actions/download-artifact from 4.2.1 to 4.3.0"
[[pull_requests]]
uid = "4779"
author_uid = "dependabot"
closes_threads = []
@@ -0,0 +1,5 @@
other = "Bump Version to v22.1"
[[pull_requests]]
uid = "4791"
author_uid = "Bibo-Joshi"
closes_threads = []
+28 -1
View File
@@ -2,9 +2,12 @@
# pylint: disable=import-error
"""Configuration for the chango changelog tool"""
import re
from collections.abc import Collection
from pathlib import Path
from typing import Optional
from chango import Version
from chango.concrete import DirectoryChanGo, DirectoryVersionScanner, HeaderVersionHistory
from chango.concrete.sections import GitHubSectionChangeNote, Section, SectionVersionNote
@@ -70,7 +73,31 @@ class ChangoSectionChangeNote(
return found or {"other"}
chango_instance = DirectoryChanGo(
class CustomChango(DirectoryChanGo):
"""Custom ChanGo class for overriding release"""
def release(self, version: Version) -> bool:
"""replace "14.5" with version.uid except in the contrib guide
then call super
"""
root = Path(__file__).parent.parent / "telegram"
python_files = root.rglob("*.py")
pattern = re.compile(r"NEXT\.VERSION")
excluded_paths = {root / "docs/source/contribute.rst"}
for file_path in python_files:
if str(file_path) in excluded_paths:
continue
content = file_path.read_text(encoding="utf-8")
modified = pattern.sub(version.uid, content)
if content != modified:
file_path.write_text(modified, encoding="utf-8")
return super().release(version)
chango_instance = CustomChango(
change_note_type=ChangoSectionChangeNote,
version_note_type=SectionVersionNote,
version_history_type=HeaderVersionHistory,
+7 -3
View File
@@ -15,12 +15,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/].
import collections.abc
import contextlib
import inspect
import re
import typing
from pathlib import Path
from typing import TYPE_CHECKING
from sphinx.application import Sphinx
@@ -37,6 +37,10 @@ from docs.auxil.kwargs_insertion import (
)
from docs.auxil.link_code import LINE_NUMBERS
if TYPE_CHECKING:
import collections.abc
ADMONITION_INSERTER = AdmonitionInserter()
# Some base classes are implementation detail
@@ -128,7 +132,7 @@ def autodoc_process_docstring(
insert_idx += len(effective_insert)
ADMONITION_INSERTER.insert_admonitions(
obj=typing.cast(collections.abc.Callable, obj),
obj=typing.cast("collections.abc.Callable", obj),
docstring_lines=lines,
)
@@ -136,7 +140,7 @@ def autodoc_process_docstring(
# (where applicable)
if what == "class":
ADMONITION_INSERTER.insert_admonitions(
obj=typing.cast(type, obj), # since "what" == class, we know it's not just object
obj=typing.cast("type", obj), # since "what" == class, we know it's not just object
docstring_lines=lines,
)
+2
View File
@@ -125,6 +125,8 @@ linkcheck_ignore = [
# 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"),
# Apparently has some human-verification check and gives 403 in the sphinx build
re.escape("https://stackoverflow.com/questions/tagged/python-telegram-bot"),
]
linkcheck_allowed_redirects = {
# Redirects to the default version are okay
+1 -1
View File
@@ -61,7 +61,7 @@ for this one, too!
:any:`examples.nestedconversationbot`
-------------------------------------
A even more complex example of a bot that uses the nested
An even more complex example of a bot that uses the nested
``ConversationHandler``\ s. While its certainly not that complex that
you couldnt built it without nested ``ConversationHanldler``\ s, it
gives a good impression on how to work with them. Of course, there is a
+54 -2
View File
@@ -161,8 +161,6 @@
- Used for unpinning a message
* - :meth:`~telegram.Bot.unpin_all_chat_messages`
- Used for unpinning all pinned chat messages
* - :meth:`~telegram.Bot.get_business_connection`
- Used for getting information about the business account.
* - :meth:`~telegram.Bot.get_user_profile_photos`
- Used for obtaining user's profile pictures
* - :meth:`~telegram.Bot.get_chat`
@@ -396,6 +394,60 @@
- Used for obtaining the bot's Telegram Stars transactions
* - :meth:`~telegram.Bot.refund_star_payment`
- Used for refunding a payment in Telegram Stars
* - :meth:`~telegram.Bot.gift_premium_subscription`
- Used for gifting Telegram Premium to another user.
.. raw:: html
</details>
<br>
.. raw:: html
<details>
<summary>Business Related Methods</summary>
.. list-table::
:align: left
:widths: 1 4
* - :meth:`~telegram.Bot.get_business_connection`
- Used for getting information about the business account.
* - :meth:`~telegram.Bot.get_business_account_gifts`
- Used for getting gifts owned by the business account.
* - :meth:`~telegram.Bot.get_business_account_star_balance`
- Used for getting the amount of Stars owned by the business account.
* - :meth:`~telegram.Bot.read_business_message`
- Used for marking a message as read.
* - :meth:`~telegram.Bot.delete_story`
- Used for deleting business stories posted by the bot.
* - :meth:`~telegram.Bot.delete_business_messages`
- Used for deleting business messages.
* - :meth:`~telegram.Bot.remove_business_account_profile_photo`
- Used for removing the business accounts profile photo
* - :meth:`~telegram.Bot.set_business_account_name`
- Used for setting the business account name.
* - :meth:`~telegram.Bot.set_business_account_username`
- Used for setting the business account username.
* - :meth:`~telegram.Bot.set_business_account_bio`
- Used for setting the business account bio.
* - :meth:`~telegram.Bot.set_business_account_gift_settings`
- Used for setting the business account gift settings.
* - :meth:`~telegram.Bot.set_business_account_profile_photo`
- Used for setting the business accounts profile photo
* - :meth:`~telegram.Bot.post_story`
- Used for posting a story on behalf of business account.
* - :meth:`~telegram.Bot.edit_story`
- Used for editing business stories posted by the bot.
* - :meth:`~telegram.Bot.convert_gift_to_stars`
- Used for converting owned reqular gifts to stars.
* - :meth:`~telegram.Bot.upgrade_gift`
- Used for upgrading owned regular gifts to unique ones.
* - :meth:`~telegram.Bot.transfer_gift`
- Used for transferring owned unique gifts to another user.
* - :meth:`~telegram.Bot.transfer_business_account_stars`
- Used for transfering Stars from the business account balance to the bot's balance.
.. raw:: html
@@ -0,0 +1,6 @@
AcceptedGiftTypes
=================
.. autoclass:: telegram.AcceptedGiftTypes
:members:
:show-inheritance:
+29
View File
@@ -4,6 +4,7 @@ Available Types
.. toctree::
:titlesonly:
telegram.acceptedgifttypes
telegram.animation
telegram.audio
telegram.birthdate
@@ -19,6 +20,7 @@ Available Types
telegram.botdescription
telegram.botname
telegram.botshortdescription
telegram.businessbotrights
telegram.businessconnection
telegram.businessintro
telegram.businesslocation
@@ -75,6 +77,7 @@ Available Types
telegram.forumtopicreopened
telegram.generalforumtopichidden
telegram.generalforumtopicunhidden
telegram.giftinfo
telegram.giveaway
telegram.giveawaycompleted
telegram.giveawaycreated
@@ -92,13 +95,20 @@ Available Types
telegram.inputpaidmedia
telegram.inputpaidmediaphoto
telegram.inputpaidmediavideo
telegram.inputprofilephoto
telegram.inputprofilephotoanimated
telegram.inputprofilephotostatic
telegram.inputpolloption
telegram.inputstorycontent
telegram.inputstorycontentphoto
telegram.inputstorycontentvideo
telegram.keyboardbutton
telegram.keyboardbuttonpolltype
telegram.keyboardbuttonrequestchat
telegram.keyboardbuttonrequestusers
telegram.linkpreviewoptions
telegram.location
telegram.locationaddress
telegram.loginurl
telegram.maybeinaccessiblemessage
telegram.menubutton
@@ -116,12 +126,17 @@ Available Types
telegram.messageoriginuser
telegram.messagereactioncountupdated
telegram.messagereactionupdated
telegram.ownedgift
telegram.ownedgiftregular
telegram.ownedgifts
telegram.ownedgiftunique
telegram.paidmedia
telegram.paidmediainfo
telegram.paidmediaphoto
telegram.paidmediapreview
telegram.paidmediapurchased
telegram.paidmediavideo
telegram.paidmessagepricechanged
telegram.photosize
telegram.poll
telegram.pollanswer
@@ -138,9 +153,23 @@ Available Types
telegram.sentwebappmessage
telegram.shareduser
telegram.story
telegram.storyarea
telegram.storyareaposition
telegram.storyareatype
telegram.storyareatypelink
telegram.storyareatypelocation
telegram.storyareatypesuggestedreaction
telegram.storyareatypeuniquegift
telegram.storyareatypeweather
telegram.switchinlinequerychosenchat
telegram.telegramobject
telegram.textquote
telegram.uniquegift
telegram.uniquegiftbackdrop
telegram.uniquegiftbackdropcolors
telegram.uniquegiftinfo
telegram.uniquegiftmodel
telegram.uniquegiftsymbol
telegram.update
telegram.user
telegram.userchatboosts
@@ -0,0 +1,6 @@
BusinessBotRights
=================
.. autoclass:: telegram.BusinessBotRights
:members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
GiftInfo
========
.. autoclass:: telegram.GiftInfo
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
InputProfilePhoto
=================
.. autoclass:: telegram.InputProfilePhoto
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
InputProfilePhotoAnimated
=========================
.. autoclass:: telegram.InputProfilePhotoAnimated
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
InputProfilePhotoStatic
=======================
.. autoclass:: telegram.InputProfilePhotoStatic
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
InputStoryContent
=================
.. autoclass:: telegram.InputStoryContent
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
InputStoryContentPhoto
======================
.. autoclass:: telegram.InputStoryContentPhoto
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
InputStoryContentVideo
======================
.. autoclass:: telegram.InputStoryContentVideo
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
LocationAddress
===============
.. autoclass:: telegram.LocationAddress
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
OwnedGift
=========
.. autoclass:: telegram.OwnedGift
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
OwnedGiftRegular
================
.. autoclass:: telegram.OwnedGiftRegular
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
OwnedGifts
==========
.. autoclass:: telegram.OwnedGifts
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
OwnedGiftUnique
===============
.. autoclass:: telegram.OwnedGiftUnique
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
PaidMessagePriceChanged
=======================
.. autoclass:: telegram.PaidMessagePriceChanged
:members:
:show-inheritance:
+1
View File
@@ -22,6 +22,7 @@ Your bot can accept payments from Telegram users. Please see the `introduction t
telegram.shippingaddress
telegram.shippingoption
telegram.shippingquery
telegram.staramount
telegram.startransaction
telegram.startransactions
telegram.successfulpayment
+6
View File
@@ -0,0 +1,6 @@
StarAmount
==========
.. autoclass:: telegram.StarAmount
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
StoryArea
=========
.. autoclass:: telegram.StoryArea
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
StoryAreaPosition
=================
.. autoclass:: telegram.StoryAreaPosition
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
StoryAreaType
=============
.. autoclass:: telegram.StoryAreaType
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
StoryAreaTypeLink
=================
.. autoclass:: telegram.StoryAreaTypeLink
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
StoryAreaTypeLocation
=====================
.. autoclass:: telegram.StoryAreaTypeLocation
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
StoryAreaTypeSuggestedReaction
==============================
.. autoclass:: telegram.StoryAreaTypeSuggestedReaction
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
StoryAreaTypeUniqueGift
=======================
.. autoclass:: telegram.StoryAreaTypeUniqueGift
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
StoryAreaTypeWeather
====================
.. autoclass:: telegram.StoryAreaTypeWeather
:members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
UniqueGift
==========
.. autoclass:: telegram.UniqueGift
:members:
:show-inheritance:
@@ -0,0 +1,7 @@
UniqueGiftBackdrop
==================
.. autoclass:: telegram.UniqueGiftBackdrop
:members:
:show-inheritance:
@@ -0,0 +1,7 @@
UniqueGiftBackdropColors
========================
.. autoclass:: telegram.UniqueGiftBackdropColors
:members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
UniqueGiftInfo
==============
.. autoclass:: telegram.UniqueGiftInfo
:members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
UniqueGiftModel
===============
.. autoclass:: telegram.UniqueGiftModel
:members:
:show-inheritance:
@@ -0,0 +1,7 @@
UniqueGiftSymbol
================
.. autoclass:: telegram.UniqueGiftSymbol
:members:
:show-inheritance:
+1 -1
View File
@@ -69,7 +69,7 @@ async def list_button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> Non
# Get the data from the callback_data.
# If you're using a type checker like MyPy, you'll have to use typing.cast
# to make the checker get the expected type of the callback_data
number, number_list = cast(tuple[int, list[int]], query.data)
number, number_list = cast("tuple[int, list[int]]", query.data)
# append the number to the list
number_list.append(number)
+1 -2
View File
@@ -125,8 +125,7 @@ line-length = 99
show-fixes = true
[tool.ruff.lint]
preview = true
explicit-preview-rules = true # TODO: Drop this when RUF022 and RUF023 are out of preview
typing-extensions = false
ignore = ["PLR2004", "PLR0911", "PLR0912", "PLR0913", "PLR0915", "PERF203"]
select = ["E", "F", "I", "PL", "UP", "RUF", "PTH", "C4", "B", "PIE", "SIM", "RET", "RSE",
"G", "ISC", "PT", "ASYNC", "TCH", "SLOT", "PERF", "PYI", "FLY", "AIR", "RUF022",
+64 -1
View File
@@ -20,6 +20,7 @@
__author__ = "devs@python-telegram-bot.org"
__all__ = (
"AcceptedGiftTypes",
"AffiliateInfo",
"Animation",
"Audio",
@@ -46,6 +47,7 @@ __all__ = (
"BotDescription",
"BotName",
"BotShortDescription",
"BusinessBotRights",
"BusinessConnection",
"BusinessIntro",
"BusinessLocation",
@@ -103,6 +105,7 @@ __all__ = (
"GeneralForumTopicHidden",
"GeneralForumTopicUnhidden",
"Gift",
"GiftInfo",
"Gifts",
"Giveaway",
"GiveawayCompleted",
@@ -150,7 +153,13 @@ __all__ = (
"InputPaidMediaPhoto",
"InputPaidMediaVideo",
"InputPollOption",
"InputProfilePhoto",
"InputProfilePhotoAnimated",
"InputProfilePhotoStatic",
"InputSticker",
"InputStoryContent",
"InputStoryContentPhoto",
"InputStoryContentVideo",
"InputTextMessageContent",
"InputVenueMessageContent",
"Invoice",
@@ -161,6 +170,7 @@ __all__ = (
"LabeledPrice",
"LinkPreviewOptions",
"Location",
"LocationAddress",
"LoginUrl",
"MaskPosition",
"MaybeInaccessibleMessage",
@@ -180,12 +190,17 @@ __all__ = (
"MessageReactionCountUpdated",
"MessageReactionUpdated",
"OrderInfo",
"OwnedGift",
"OwnedGiftRegular",
"OwnedGiftUnique",
"OwnedGifts",
"PaidMedia",
"PaidMediaInfo",
"PaidMediaPhoto",
"PaidMediaPreview",
"PaidMediaPurchased",
"PaidMediaVideo",
"PaidMessagePriceChanged",
"PassportData",
"PassportElementError",
"PassportElementErrorDataField",
@@ -227,11 +242,20 @@ __all__ = (
"ShippingAddress",
"ShippingOption",
"ShippingQuery",
"StarAmount",
"StarTransaction",
"StarTransactions",
"Sticker",
"StickerSet",
"Story",
"StoryArea",
"StoryAreaPosition",
"StoryAreaType",
"StoryAreaTypeLink",
"StoryAreaTypeLocation",
"StoryAreaTypeSuggestedReaction",
"StoryAreaTypeUniqueGift",
"StoryAreaTypeWeather",
"SuccessfulPayment",
"SwitchInlineQueryChosenChat",
"TelegramObject",
@@ -244,6 +268,12 @@ __all__ = (
"TransactionPartnerTelegramAds",
"TransactionPartnerTelegramApi",
"TransactionPartnerUser",
"UniqueGift",
"UniqueGiftBackdrop",
"UniqueGiftBackdropColors",
"UniqueGiftInfo",
"UniqueGiftModel",
"UniqueGiftSymbol",
"Update",
"User",
"UserChatBoosts",
@@ -272,6 +302,7 @@ __all__ = (
"warnings",
)
from telegram._payment.stars.staramount import StarAmount
from telegram._payment.stars.startransactions import StarTransaction, StarTransactions
from telegram._payment.stars.transactionpartner import (
TransactionPartner,
@@ -301,6 +332,7 @@ from ._botcommandscope import (
from ._botdescription import BotDescription, BotShortDescription
from ._botname import BotName
from ._business import (
BusinessBotRights,
BusinessConnection,
BusinessIntro,
BusinessLocation,
@@ -352,6 +384,11 @@ from ._chatpermissions import ChatPermissions
from ._choseninlineresult import ChosenInlineResult
from ._copytextbutton import CopyTextButton
from ._dice import Dice
from ._files._inputstorycontent import (
InputStoryContent,
InputStoryContentPhoto,
InputStoryContentVideo,
)
from ._files.animation import Animation
from ._files.audio import Audio
from ._files.chatphoto import ChatPhoto
@@ -370,6 +407,11 @@ from ._files.inputmedia import (
InputPaidMediaPhoto,
InputPaidMediaVideo,
)
from ._files.inputprofilephoto import (
InputProfilePhoto,
InputProfilePhotoAnimated,
InputProfilePhotoStatic,
)
from ._files.inputsticker import InputSticker
from ._files.location import Location
from ._files.photosize import PhotoSize
@@ -391,7 +433,7 @@ from ._forumtopic import (
from ._games.callbackgame import CallbackGame
from ._games.game import Game
from ._games.gamehighscore import GameHighScore
from ._gifts import Gift, Gifts
from ._gifts import AcceptedGiftTypes, Gift, GiftInfo, Gifts
from ._giveaway import Giveaway, GiveawayCompleted, GiveawayCreated, GiveawayWinners
from ._inline.inlinekeyboardbutton import InlineKeyboardButton
from ._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
@@ -443,6 +485,7 @@ from ._messageorigin import (
MessageOriginUser,
)
from ._messagereactionupdated import MessageReactionCountUpdated, MessageReactionUpdated
from ._ownedgift import OwnedGift, OwnedGiftRegular, OwnedGifts, OwnedGiftUnique
from ._paidmedia import (
PaidMedia,
PaidMediaInfo,
@@ -451,6 +494,7 @@ from ._paidmedia import (
PaidMediaPurchased,
PaidMediaVideo,
)
from ._paidmessagepricechanged import PaidMessagePriceChanged
from ._passport.credentials import (
Credentials,
DataCredentials,
@@ -506,8 +550,27 @@ from ._replykeyboardremove import ReplyKeyboardRemove
from ._sentwebappmessage import SentWebAppMessage
from ._shared import ChatShared, SharedUser, UsersShared
from ._story import Story
from ._storyarea import (
LocationAddress,
StoryArea,
StoryAreaPosition,
StoryAreaType,
StoryAreaTypeLink,
StoryAreaTypeLocation,
StoryAreaTypeSuggestedReaction,
StoryAreaTypeUniqueGift,
StoryAreaTypeWeather,
)
from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
from ._telegramobject import TelegramObject
from ._uniquegift import (
UniqueGift,
UniqueGiftBackdrop,
UniqueGiftBackdropColors,
UniqueGiftInfo,
UniqueGiftModel,
UniqueGiftSymbol,
)
from ._update import Update
from ._user import User
from ._userprofilephotos import UserProfilePhotos
+1026 -13
View File
File diff suppressed because it is too large Load Diff
+208 -10
View File
@@ -30,20 +30,172 @@ from telegram._user import User
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
from telegram._utils.warnings import warn
from telegram._utils.warnings_transition import (
build_deprecation_warning_message,
warn_about_deprecated_attr_in_property,
)
from telegram.warnings import PTBDeprecationWarning
if TYPE_CHECKING:
from telegram import Bot
class BusinessBotRights(TelegramObject):
"""
This object represents the rights of a business bot.
Objects of this class are comparable in terms of equality.
Two objects of this class are considered equal, if all their attributes are equal.
.. versionadded:: 22.1
Args:
can_reply (:obj:`bool`, optional): True, if the bot can send and edit messages in the
private chats that had incoming messages in the last 24 hours.
can_read_messages (:obj:`bool`, optional): True, if the bot can mark incoming private
messages as read.
can_delete_sent_messages (:obj:`bool`, optional): True, if the bot can delete messages
sent by the bot.
can_delete_all_messages (:obj:`bool`, optional): True, if the bot can delete all private
messages in managed chats.
can_edit_name (:obj:`bool`, optional): True, if the bot can edit the first and last name
of the business account.
can_edit_bio (:obj:`bool`, optional): True, if the bot can edit the bio of the
business account.
can_edit_profile_photo (:obj:`bool`, optional): True, if the bot can edit the profile
photo of the business account.
can_edit_username (:obj:`bool`, optional): True, if the bot can edit the username of the
business account.
can_change_gift_settings (:obj:`bool`, optional): True, if the bot can change the privacy
settings pertaining to gifts for the business account.
can_view_gifts_and_stars (:obj:`bool`, optional): True, if the bot can view gifts and the
amount of Telegram Stars owned by the business account.
can_convert_gifts_to_stars (:obj:`bool`, optional): True, if the bot can convert regular
gifts owned by the business account to Telegram Stars.
can_transfer_and_upgrade_gifts (:obj:`bool`, optional): True, if the bot can transfer and
upgrade gifts owned by the business account.
can_transfer_stars (:obj:`bool`, optional): True, if the bot can transfer Telegram Stars
received by the business account to its own account, or use them to upgrade and
transfer gifts.
can_manage_stories (:obj:`bool`, optional): True, if the bot can post, edit and delete
stories on behalf of the business account.
Attributes:
can_reply (:obj:`bool`): Optional. True, if the bot can send and edit messages in the
private chats that had incoming messages in the last 24 hours.
can_read_messages (:obj:`bool`): Optional. True, if the bot can mark incoming private
messages as read.
can_delete_sent_messages (:obj:`bool`): Optional. True, if the bot can delete messages
sent by the bot.
can_delete_all_messages (:obj:`bool`): Optional. True, if the bot can delete all private
messages in managed chats.
can_edit_name (:obj:`bool`): Optional. True, if the bot can edit the first and last name
of the business account.
can_edit_bio (:obj:`bool`): Optional. True, if the bot can edit the bio of the
business account.
can_edit_profile_photo (:obj:`bool`): Optional. True, if the bot can edit the profile
photo of the business account.
can_edit_username (:obj:`bool`): Optional. True, if the bot can edit the username of the
business account.
can_change_gift_settings (:obj:`bool`): Optional. True, if the bot can change the privacy
settings pertaining to gifts for the business account.
can_view_gifts_and_stars (:obj:`bool`): Optional. True, if the bot can view gifts and the
amount of Telegram Stars owned by the business account.
can_convert_gifts_to_stars (:obj:`bool`): Optional. True, if the bot can convert regular
gifts owned by the business account to Telegram Stars.
can_transfer_and_upgrade_gifts (:obj:`bool`): Optional. True, if the bot can transfer and
upgrade gifts owned by the business account.
can_transfer_stars (:obj:`bool`): Optional. True, if the bot can transfer Telegram Stars
received by the business account to its own account, or use them to upgrade and
transfer gifts.
can_manage_stories (:obj:`bool`): Optional. True, if the bot can post, edit and delete
stories on behalf of the business account.
"""
__slots__ = (
"can_change_gift_settings",
"can_convert_gifts_to_stars",
"can_delete_all_messages",
"can_delete_sent_messages",
"can_edit_bio",
"can_edit_name",
"can_edit_profile_photo",
"can_edit_username",
"can_manage_stories",
"can_read_messages",
"can_reply",
"can_transfer_and_upgrade_gifts",
"can_transfer_stars",
"can_view_gifts_and_stars",
)
def __init__(
self,
can_reply: Optional[bool] = None,
can_read_messages: Optional[bool] = None,
can_delete_sent_messages: Optional[bool] = None,
can_delete_all_messages: Optional[bool] = None,
can_edit_name: Optional[bool] = None,
can_edit_bio: Optional[bool] = None,
can_edit_profile_photo: Optional[bool] = None,
can_edit_username: Optional[bool] = None,
can_change_gift_settings: Optional[bool] = None,
can_view_gifts_and_stars: Optional[bool] = None,
can_convert_gifts_to_stars: Optional[bool] = None,
can_transfer_and_upgrade_gifts: Optional[bool] = None,
can_transfer_stars: Optional[bool] = None,
can_manage_stories: Optional[bool] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.can_reply: Optional[bool] = can_reply
self.can_read_messages: Optional[bool] = can_read_messages
self.can_delete_sent_messages: Optional[bool] = can_delete_sent_messages
self.can_delete_all_messages: Optional[bool] = can_delete_all_messages
self.can_edit_name: Optional[bool] = can_edit_name
self.can_edit_bio: Optional[bool] = can_edit_bio
self.can_edit_profile_photo: Optional[bool] = can_edit_profile_photo
self.can_edit_username: Optional[bool] = can_edit_username
self.can_change_gift_settings: Optional[bool] = can_change_gift_settings
self.can_view_gifts_and_stars: Optional[bool] = can_view_gifts_and_stars
self.can_convert_gifts_to_stars: Optional[bool] = can_convert_gifts_to_stars
self.can_transfer_and_upgrade_gifts: Optional[bool] = can_transfer_and_upgrade_gifts
self.can_transfer_stars: Optional[bool] = can_transfer_stars
self.can_manage_stories: Optional[bool] = can_manage_stories
self._id_attrs = (
self.can_reply,
self.can_read_messages,
self.can_delete_sent_messages,
self.can_delete_all_messages,
self.can_edit_name,
self.can_edit_bio,
self.can_edit_profile_photo,
self.can_edit_username,
self.can_change_gift_settings,
self.can_view_gifts_and_stars,
self.can_convert_gifts_to_stars,
self.can_transfer_and_upgrade_gifts,
self.can_transfer_stars,
self.can_manage_stories,
)
self._freeze()
class BusinessConnection(TelegramObject):
"""
Describes the connection of the bot with a business account.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal if their :attr:`id`, :attr:`user`, :attr:`user_chat_id`, :attr:`date`,
:attr:`can_reply`, and :attr:`is_enabled` are equal.
:attr:`rights`, and :attr:`is_enabled` are equal.
.. versionadded:: 21.1
.. versionchanged:: 22.1
Equality comparison now considers :attr:`rights` instead of :attr:`can_reply`.
Args:
id (:obj:`str`): Unique identifier of the business connection.
@@ -51,9 +203,15 @@ class BusinessConnection(TelegramObject):
user_chat_id (:obj:`int`): Identifier of a private chat with the user who created the
business connection.
date (:obj:`datetime.datetime`): Date the connection was established in Unix time.
can_reply (:obj:`bool`): True, if the bot can act on behalf of the business account in
chats that were active in the last 24 hours.
can_reply (:obj:`bool`, optional): True, if the bot can act on behalf of the business
account in chats that were active in the last 24 hours.
.. deprecated:: 22.1
Bot API 9.0 deprecated this argument in favor of :paramref:`rights`.
is_enabled (:obj:`bool`): True, if the connection is active.
rights (:class:`BusinessBotRights`, optional): Rights of the business bot.
.. versionadded:: 22.1
Attributes:
id (:obj:`str`): Unique identifier of the business connection.
@@ -61,16 +219,18 @@ class BusinessConnection(TelegramObject):
user_chat_id (:obj:`int`): Identifier of a private chat with the user who created the
business connection.
date (:obj:`datetime.datetime`): Date the connection was established in Unix time.
can_reply (:obj:`bool`): True, if the bot can act on behalf of the business account in
chats that were active in the last 24 hours.
is_enabled (:obj:`bool`): True, if the connection is active.
rights (:class:`BusinessBotRights`): Optional. Rights of the business bot.
.. versionadded:: 22.1
"""
__slots__ = (
"can_reply",
"_can_reply",
"date",
"id",
"is_enabled",
"rights",
"user",
"user_chat_id",
)
@@ -81,30 +241,67 @@ class BusinessConnection(TelegramObject):
user: "User",
user_chat_id: int,
date: dtm.datetime,
can_reply: bool,
is_enabled: bool,
can_reply: Optional[bool] = None,
# temporarily optional to account for changed signature
# tags: deprecated 22.1; bot api 9.0
is_enabled: Optional[bool] = None,
rights: Optional[BusinessBotRights] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
if is_enabled is None:
raise TypeError("Missing required argument `is_enabled`")
if can_reply is not None:
warn(
PTBDeprecationWarning(
version="22.1",
message=build_deprecation_warning_message(
deprecated_name="can_reply",
new_name="rights",
bot_api_version="9.0",
object_type="parameter",
),
),
stacklevel=2,
)
super().__init__(api_kwargs=api_kwargs)
self.id: str = id
self.user: User = user
self.user_chat_id: int = user_chat_id
self.date: dtm.datetime = date
self.can_reply: bool = can_reply
self._can_reply: Optional[bool] = can_reply
self.is_enabled: bool = is_enabled
self.rights: Optional[BusinessBotRights] = rights
self._id_attrs = (
self.id,
self.user,
self.user_chat_id,
self.date,
self.can_reply,
self.rights,
self.is_enabled,
)
self._freeze()
@property
def can_reply(self) -> Optional[bool]:
""":obj:`bool`: Optional. True, if the bot can act on behalf of the business account in
chats that were active in the last 24 hours.
.. deprecated:: 22.1
Bot API 9.0 deprecated this argument in favor of :attr:`rights`
"""
warn_about_deprecated_attr_in_property(
deprecated_attr_name="can_reply",
new_attr_name="rights",
bot_api_version="9.0",
ptb_version="22.1",
)
return self._can_reply
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "BusinessConnection":
"""See :meth:`telegram.TelegramObject.de_json`."""
@@ -115,6 +312,7 @@ class BusinessConnection(TelegramObject):
data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
data["user"] = de_json_optional(data.get("user"), User, bot)
data["rights"] = de_json_optional(data.get("rights"), BusinessBotRights, bot)
return super().de_json(data=data, bot=bot)
+69
View File
@@ -3506,6 +3506,41 @@ class _ChatBase(TelegramObject):
**{"chat_id" if self.type == Chat.CHANNEL else "user_id": self.id},
)
async def transfer_gift(
self,
business_connection_id: str,
owned_gift_id: str,
star_count: Optional[int] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: Optional[JSONDict] = None,
) -> bool:
"""Shortcut for::
await bot.transfer_gift(new_owner_chat_id=update.effective_chat.id, *args, **kwargs )
For the documentation of the arguments, please see :meth:`telegram.Bot.transfer_gift`.
.. versionadded:: 22.1
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().transfer_gift(
new_owner_chat_id=self.id,
business_connection_id=business_connection_id,
owned_gift_id=owned_gift_id,
star_count=star_count,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def verify(
self,
custom_description: Optional[str] = None,
@@ -3568,6 +3603,40 @@ class _ChatBase(TelegramObject):
api_kwargs=api_kwargs,
)
async def read_business_message(
self,
business_connection_id: str,
message_id: int,
*,
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.read_business_message(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.read_business_message`.
.. versionadded:: 22.1
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().read_business_message(
chat_id=self.id,
business_connection_id=business_connection_id,
message_id=message_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
class Chat(_ChatBase):
"""This object represents a chat.
+64 -5
View File
@@ -27,10 +27,17 @@ from telegram._chat import Chat, _ChatBase
from telegram._chatlocation import ChatLocation
from telegram._chatpermissions import ChatPermissions
from telegram._files.chatphoto import ChatPhoto
from telegram._gifts import AcceptedGiftTypes
from telegram._reaction import ReactionType
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
from telegram._utils.warnings import warn
from telegram._utils.warnings_transition import (
build_deprecation_warning_message,
warn_about_deprecated_attr_in_property,
)
from telegram.warnings import PTBDeprecationWarning
if TYPE_CHECKING:
from telegram import Bot, BusinessIntro, BusinessLocation, BusinessOpeningHours, Message
@@ -64,6 +71,10 @@ class ChatFullInfo(_ChatBase):
message in the chat.
.. versionadded:: 21.2
accepted_gift_types (:class:`telegram.AcceptedGiftTypes`): Information about types of
gifts that are accepted by the chat or by the corresponding user for private chats.
.. versionadded:: 22.1
title (:obj:`str`, optional): Title, for supergroups, channels and group chats.
username (:obj:`str`, optional): Username, for private chats, supergroups and channels if
available.
@@ -204,6 +215,10 @@ class ChatFullInfo(_ChatBase):
.. versionadded:: 21.11
.. deprecated:: 22.1
Bot API 9.0 introduced :paramref:`accepted_gift_types`, replacing this argument.
Hence, this argument will be removed in future versions.
Attributes:
id (:obj:`int`): Unique identifier for this chat.
type (:obj:`str`): Type of chat, can be either :attr:`PRIVATE`, :attr:`GROUP`,
@@ -218,6 +233,10 @@ class ChatFullInfo(_ChatBase):
message in the chat.
.. versionadded:: 21.2
accepted_gift_types (:class:`telegram.AcceptedGiftTypes`): Information about types of
gifts that are accepted by the chat or by the corresponding user for private chats.
.. versionadded:: 22.1
title (:obj:`str`, optional): Title, for supergroups, channels and group chats.
username (:obj:`str`, optional): Username, for private chats, supergroups and channels if
available.
@@ -357,16 +376,15 @@ 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
"""
__slots__ = (
"_can_send_gift",
"accent_color_id",
"accepted_gift_types",
"active_usernames",
"available_reactions",
"background_custom_emoji_id",
@@ -375,7 +393,6 @@ 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",
@@ -452,7 +469,10 @@ class ChatFullInfo(_ChatBase):
linked_chat_id: Optional[int] = None,
location: Optional[ChatLocation] = None,
can_send_paid_media: Optional[bool] = None,
# tags: deprecated 22.1; bot api 9.0
can_send_gift: Optional[bool] = None,
# temporarily optional to account for changed signature
accepted_gift_types: Optional[AcceptedGiftTypes] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
@@ -466,6 +486,22 @@ class ChatFullInfo(_ChatBase):
is_forum=is_forum,
api_kwargs=api_kwargs,
)
if accepted_gift_types is None:
raise TypeError("`accepted_gift_type` is a required argument since Bot API 9.0")
if can_send_gift is not None:
warn(
PTBDeprecationWarning(
"22.1",
build_deprecation_warning_message(
deprecated_name="can_send_gift",
new_name="accepted_gift_types",
object_type="parameter",
bot_api_version="9.0",
),
),
stacklevel=2,
)
# Required and unique to this class-
with self._unfrozen():
@@ -518,7 +554,27 @@ 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
self._can_send_gift: Optional[bool] = can_send_gift
self.accepted_gift_types: AcceptedGiftTypes = accepted_gift_types
@property
def can_send_gift(self) -> Optional[bool]:
"""
:obj:`bool`: Optional. :obj:`True`, if gifts can be sent to the chat.
.. deprecated:: 22.1
As Bot API 9.0 replaces this attribute with :attr:`accepted_gift_types`, this attribute
will be removed in future versions.
"""
warn_about_deprecated_attr_in_property(
deprecated_attr_name="can_send_gift",
new_attr_name="accepted_gift_types",
bot_api_version="9.0",
ptb_version="22.1",
stacklevel=2,
)
return self._can_send_gift
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatFullInfo":
@@ -533,6 +589,9 @@ class ChatFullInfo(_ChatBase):
)
data["photo"] = de_json_optional(data.get("photo"), ChatPhoto, bot)
data["accepted_gift_types"] = de_json_optional(
data.get("accepted_gift_types"), AcceptedGiftTypes, bot
)
from telegram import ( # pylint: disable=import-outside-toplevel
BusinessIntro,
+175
View File
@@ -0,0 +1,175 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# 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
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains objects that represent paid media in Telegram."""
import datetime as dtm
from typing import Final, Optional, Union
from telegram import constants
from telegram._files.inputfile import InputFile
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.files import parse_file_input
from telegram._utils.types import FileInput, JSONDict
class InputStoryContent(TelegramObject):
"""This object describes the content of a story to post. Currently, it can be one of:
* :class:`telegram.InputStoryContentPhoto`
* :class:`telegram.InputStoryContentVideo`
.. versionadded:: 22.1
Args:
type (:obj:`str`): Type of the content.
Attributes:
type (:obj:`str`): Type of the content.
"""
__slots__ = ("type",)
PHOTO: Final[str] = constants.InputStoryContentType.PHOTO
""":const:`telegram.constants.InputStoryContentType.PHOTO`"""
VIDEO: Final[str] = constants.InputStoryContentType.VIDEO
""":const:`telegram.constants.InputStoryContentType.VIDEO`"""
def __init__(
self,
type: str, # pylint: disable=redefined-builtin
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(api_kwargs=api_kwargs)
self.type: str = enum.get_member(constants.InputStoryContentType, type, type)
self._freeze()
@staticmethod
def _parse_file_input(file_input: FileInput) -> Union[str, InputFile]:
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
return parse_file_input(file_input, attach=True, local_mode=True)
class InputStoryContentPhoto(InputStoryContent):
"""Describes a photo to post as a story.
.. versionadded:: 22.1
Args:
photo (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
optional): The photo to post as a story. The photo must be of the
size :tg-const:`telegram.constants.InputStoryContentLimit.PHOTO_WIDTH`
x :tg-const:`telegram.constants.InputStoryContentLimit.PHOTO_HEIGHT` and must not
exceed :tg-const:`telegram.constants.InputStoryContentLimit.PHOTOSIZE_UPLOAD` MB.
|uploadinputnopath|.
Attributes:
type (:obj:`str`): Type of the content, must be :attr:`~telegram.InputStoryContent.PHOTO`.
photo (:class:`telegram.InputFile`): The photo to post as a story. The photo must be of the
size :tg-const:`telegram.constants.InputStoryContentLimit.PHOTO_WIDTH`
x :tg-const:`telegram.constants.InputStoryContentLimit.PHOTO_HEIGHT` and must not
exceed :tg-const:`telegram.constants.InputStoryContentLimit.PHOTOSIZE_UPLOAD` MB.
"""
__slots__ = ("photo",)
def __init__(
self,
photo: FileInput,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(type=InputStoryContent.PHOTO, api_kwargs=api_kwargs)
with self._unfrozen():
self.photo: Union[str, InputFile] = self._parse_file_input(photo)
class InputStoryContentVideo(InputStoryContent):
"""
Describes a video to post as a story.
.. versionadded:: 22.1
Args:
video (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
optional): The video to post as a story. The video must be of
the size :tg-const:`telegram.constants.InputStoryContentLimit.VIDEO_WIDTH`
x :tg-const:`telegram.constants.InputStoryContentLimit.VIDEO_HEIGHT`,
streamable, encoded with ``H.265`` codec, with key frames added
each second in the ``MPEG4`` format, and must not exceed
:tg-const:`telegram.constants.InputStoryContentLimit.VIDEOSIZE_UPLOAD` MB.
|uploadinputnopath|.
duration (:class:`datetime.timedelta` | :obj:`int` | :obj:`float`, optional): Precise
duration of the video in seconds;
0-:tg-const:`telegram.constants.InputStoryContentLimit.MAX_VIDEO_DURATION`
cover_frame_timestamp (:class:`datetime.timedelta` | :obj:`int` | :obj:`float`, optional):
Timestamp in seconds of the frame that will be used as the static cover for the story.
Defaults to ``0.0``.
is_animation (:obj:`bool`, optional): Pass :obj:`True` if the video has no sound
Attributes:
type (:obj:`str`): Type of the content, must be :attr:`~telegram.InputStoryContent.VIDEO`.
video (:class:`telegram.InputFile`): The video to post as a story. The video must be of
the size :tg-const:`telegram.constants.InputStoryContentLimit.VIDEO_WIDTH`
x :tg-const:`telegram.constants.InputStoryContentLimit.VIDEO_HEIGHT`,
streamable, encoded with ``H.265`` codec, with key frames added
each second in the ``MPEG4`` format, and must not exceed
:tg-const:`telegram.constants.InputStoryContentLimit.VIDEOSIZE_UPLOAD` MB.
duration (:class:`datetime.timedelta`): Optional. Precise duration of the video in seconds;
0-:tg-const:`telegram.constants.InputStoryContentLimit.MAX_VIDEO_DURATION`
cover_frame_timestamp (:class:`datetime.timedelta`): Optional. Timestamp in seconds of the
frame that will be used as the static cover for the story. Defaults to ``0.0``.
is_animation (:obj:`bool`): Optional. Pass :obj:`True` if the video has no sound
"""
__slots__ = ("cover_frame_timestamp", "duration", "is_animation", "video")
def __init__(
self,
video: FileInput,
duration: Optional[Union[float, dtm.timedelta]] = None,
cover_frame_timestamp: Optional[Union[float, dtm.timedelta]] = None,
is_animation: Optional[bool] = None,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(type=InputStoryContent.VIDEO, api_kwargs=api_kwargs)
with self._unfrozen():
self.video: Union[str, InputFile] = self._parse_file_input(video)
self.duration: Optional[dtm.timedelta] = self._parse_period_arg(duration)
self.cover_frame_timestamp: Optional[dtm.timedelta] = self._parse_period_arg(
cover_frame_timestamp
)
self.is_animation: Optional[bool] = is_animation
# This helper is temporarly here until we can use `argumentparsing.parse_period_arg`
# from https://github.com/python-telegram-bot/python-telegram-bot/pull/4750
@staticmethod
def _parse_period_arg(arg: Optional[Union[float, dtm.timedelta]]) -> Optional[dtm.timedelta]:
if arg is None:
return None
if isinstance(arg, dtm.timedelta):
return arg
return dtm.timedelta(seconds=arg)
+8 -16
View File
@@ -51,13 +51,8 @@ class InputMedia(TelegramObject):
Args:
media_type (:obj:`str`): Type of media that the instance represents.
media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
:class:`pathlib.Path` | :class:`telegram.Animation` | :class:`telegram.Audio` | \
:class:`telegram.Document` | :class:`telegram.PhotoSize` | \
:class:`telegram.Video`): File to send.
media (:obj:`str` | :class:`~telegram.InputFile`): File to send.
|fileinputnopath|
Lastly you can pass an existing telegram media object of the corresponding type
to send.
caption (:obj:`str`, optional): Caption of the media to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
parsing.
@@ -89,7 +84,7 @@ class InputMedia(TelegramObject):
def __init__(
self,
media_type: str,
media: Union[str, InputFile, MediaType],
media: Union[str, InputFile],
caption: Optional[str] = None,
caption_entities: Optional[Sequence[MessageEntity]] = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
@@ -98,7 +93,7 @@ class InputMedia(TelegramObject):
):
super().__init__(api_kwargs=api_kwargs)
self.type: str = enum.get_member(constants.InputMediaType, media_type, media_type)
self.media: Union[str, InputFile, Animation, Audio, Document, PhotoSize, Video] = media
self.media: Union[str, InputFile] = media
self.caption: Optional[str] = caption
self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
self.parse_mode: ODVInput[str] = parse_mode
@@ -120,8 +115,8 @@ class InputPaidMedia(TelegramObject):
"""
Base class for Telegram InputPaidMedia Objects. Currently, it can be one of:
* :class:`telegram.InputMediaPhoto`
* :class:`telegram.InputMediaVideo`
* :class:`telegram.InputPaidMediaPhoto`
* :class:`telegram.InputPaidMediaVideo`
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
@@ -129,11 +124,8 @@ class InputPaidMedia(TelegramObject):
Args:
type (:obj:`str`): Type of media that the instance represents.
media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
:class:`pathlib.Path` | :class:`telegram.PhotoSize` | :class:`telegram.Video`): File
media (:obj:`str` | :class:`~telegram.InputFile`): File
to send. |fileinputnopath|
Lastly you can pass an existing telegram media object of the corresponding type
to send.
Attributes:
type (:obj:`str`): Type of the input media.
@@ -150,13 +142,13 @@ class InputPaidMedia(TelegramObject):
def __init__(
self,
type: str, # pylint: disable=redefined-builtin
media: Union[str, InputFile, PhotoSize, Video],
media: Union[str, InputFile],
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.type: str = enum.get_member(constants.InputPaidMediaType, type, type)
self.media: Union[str, InputFile, PhotoSize, Video] = media
self.media: Union[str, InputFile] = media
self._freeze()
+142
View File
@@ -0,0 +1,142 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# 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
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an objects that represents a InputProfilePhoto and subclasses."""
import datetime as dtm
from typing import TYPE_CHECKING, Optional, Union
from telegram import constants
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.files import parse_file_input
from telegram._utils.types import FileInput, JSONDict
if TYPE_CHECKING:
from telegram import InputFile
class InputProfilePhoto(TelegramObject):
"""This object describes a profile photo to set. Currently, it can be one of
* :class:`InputProfilePhotoStatic`
* :class:`InputProfilePhotoAnimated`
.. versionadded:: 22.1
Args:
type (:obj:`str`): Type of the profile photo.
Attributes:
type (:obj:`str`): Type of the profile photo.
"""
STATIC = constants.InputProfilePhotoType.STATIC
""":obj:`str`: :tg-const:`telegram.constants.InputProfilePhotoType.STATIC`."""
ANIMATED = constants.InputProfilePhotoType.ANIMATED
""":obj:`str`: :tg-const:`telegram.constants.InputProfilePhotoType.ANIMATED`."""
__slots__ = ("type",)
def __init__(
self,
type: str, # pylint: disable=redefined-builtin
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.type: str = enum.get_member(constants.InputProfilePhotoType, type, type)
self._freeze()
class InputProfilePhotoStatic(InputProfilePhoto):
"""A static profile photo in the .JPG format.
.. versionadded:: 22.1
Args:
photo (:term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
:class:`pathlib.Path`): The static profile photo. |uploadinputnopath|
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputProfilePhotoType.STATIC`.
photo (:class:`telegram.InputFile` | :obj:`str`): The static profile photo.
"""
__slots__ = ("photo",)
def __init__(
self,
photo: FileInput,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(type=constants.InputProfilePhotoType.STATIC, api_kwargs=api_kwargs)
with self._unfrozen():
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
self.photo: Union[str, InputFile] = parse_file_input(
photo, attach=True, local_mode=True
)
class InputProfilePhotoAnimated(InputProfilePhoto):
"""An animated profile photo in the MPEG4 format.
.. versionadded:: 22.1
Args:
animation (:term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
:class:`pathlib.Path`): The animated profile photo. |uploadinputnopath|
main_frame_timestamp (:class:`datetime.timedelta` | :obj:`int` | :obj:`float`, optional):
Timestamp in seconds of the frame that will be used as the static profile photo.
Defaults to ``0.0``.
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputProfilePhotoType.ANIMATED`.
animation (:class:`telegram.InputFile` | :obj:`str`): The animated profile photo.
main_frame_timestamp (:class:`datetime.timedelta`): Optional. Timestamp in seconds of the
frame that will be used as the static profile photo. Defaults to ``0.0``.
"""
__slots__ = ("animation", "main_frame_timestamp")
def __init__(
self,
animation: FileInput,
main_frame_timestamp: Union[float, dtm.timedelta, None] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(type=constants.InputProfilePhotoType.ANIMATED, api_kwargs=api_kwargs)
with self._unfrozen():
# We use local_mode=True because we don't have access to the actual setting and want
# things to work in local mode.
self.animation: Union[str, InputFile] = parse_file_input(
animation, attach=True, local_mode=True
)
if isinstance(main_frame_timestamp, dtm.timedelta):
self.main_frame_timestamp: Optional[dtm.timedelta] = main_frame_timestamp
elif main_frame_timestamp is None:
self.main_frame_timestamp = None
else:
self.main_frame_timestamp = dtm.timedelta(seconds=main_frame_timestamp)
+210
View File
@@ -22,8 +22,10 @@ from collections.abc import Sequence
from typing import TYPE_CHECKING, Optional
from telegram._files.sticker import Sticker
from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.entities import parse_message_entities, parse_message_entity
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
@@ -145,3 +147,211 @@ class Gifts(TelegramObject):
data["gifts"] = de_list_optional(data.get("gifts"), Gift, bot)
return super().de_json(data=data, bot=bot)
class GiftInfo(TelegramObject):
"""Describes a service message about a regular gift that was sent or received.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal if their :attr:`gift` is equal.
.. versionadded:: 22.1
Args:
gift (:class:`Gift`): Information about the gift.
owned_gift_id (:obj:`str`, optional): Unique identifier of the received gift for the bot;
only present for gifts received on behalf of business accounts
convert_star_count (:obj:`int`, optional) Number of Telegram Stars that can be claimed by
the receiver by converting the gift; omitted if conversion to Telegram Stars
is impossible
prepaid_upgrade_star_count (:obj:`int`, optional): Number of Telegram Stars that were
prepaid by the sender for the ability to upgrade the gift
can_be_upgraded (:obj:`bool`, optional): :obj:`True`, if the gift can be upgraded
to a unique gift.
text (:obj:`str`, optional): Text of the message that was added to the gift.
entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities that
appear in the text.
is_private (:obj:`bool`, optional): :obj:`True`, if the sender and gift text are
shown only to the gift receiver; otherwise, everyone will be able to see them.
Attributes:
gift (:class:`Gift`): Information about the gift.
owned_gift_id (:obj:`str`): Optional. Unique identifier of the received gift for the bot;
only present for gifts received on behalf of business accounts
convert_star_count (:obj:`int`): Optional. Number of Telegram Stars that can be claimed by
the receiver by converting the gift; omitted if conversion to Telegram Stars
is impossible
prepaid_upgrade_star_count (:obj:`int`): Optional. Number of Telegram Stars that were
prepaid by the sender for the ability to upgrade the gift
can_be_upgraded (:obj:`bool`): Optional. :obj:`True`, if the gift can be upgraded
to a unique gift.
text (:obj:`str`): Optional. Text of the message that was added to the gift.
entities (Sequence[:class:`telegram.MessageEntity`]): Optional. Special entities that
appear in the text.
is_private (:obj:`bool`): Optional. :obj:`True`, if the sender and gift text are
shown only to the gift receiver; otherwise, everyone will be able to see them.
"""
__slots__ = (
"can_be_upgraded",
"convert_star_count",
"entities",
"gift",
"is_private",
"owned_gift_id",
"prepaid_upgrade_star_count",
"text",
)
def __init__(
self,
gift: Gift,
owned_gift_id: Optional[str] = None,
convert_star_count: Optional[int] = None,
prepaid_upgrade_star_count: Optional[int] = None,
can_be_upgraded: Optional[bool] = None,
text: Optional[str] = None,
entities: Optional[Sequence[MessageEntity]] = None,
is_private: Optional[bool] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.gift: Gift = gift
# Optional
self.owned_gift_id: Optional[str] = owned_gift_id
self.convert_star_count: Optional[int] = convert_star_count
self.prepaid_upgrade_star_count: Optional[int] = prepaid_upgrade_star_count
self.can_be_upgraded: Optional[bool] = can_be_upgraded
self.text: Optional[str] = text
self.entities: tuple[MessageEntity, ...] = parse_sequence_arg(entities)
self.is_private: Optional[bool] = is_private
self._id_attrs = (self.gift,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "GiftInfo":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["gift"] = de_json_optional(data.get("gift"), Gift, bot)
data["entities"] = de_list_optional(data.get("entities"), MessageEntity, bot)
return super().de_json(data=data, bot=bot)
def parse_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`text`
from a given :class:`telegram.MessageEntity` of :attr:`entities`.
Note:
This method is present because Telegram calculates the offset and length in
UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
(That is, you can't just slice ``Message.text`` with the offset and length.)
Args:
entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
be an entity that belongs to :attr:`entities`.
Returns:
:obj:`str`: The text of the given entity.
Raises:
RuntimeError: If the gift info has no text.
"""
if not self.text:
raise RuntimeError("This GiftInfo has no 'text'.")
return parse_message_entity(self.text, entity)
def parse_entities(self, types: Optional[list[str]] = None) -> dict[MessageEntity, str]:
"""
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
It contains entities from this gift info's text filtered by their ``type`` attribute as
the key, and the text that each entity belongs to as the value of the :obj:`dict`.
Note:
This method should always be used instead of the :attr:`entities`
attribute, since it calculates the correct substring from the message text based on
UTF-16 codepoints. See :attr:`parse_entity` for more info.
Args:
types (list[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the
``type`` attribute of an entity is contained in this list, it will be returned.
Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`.
Returns:
dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
the text that belongs to them, calculated based on UTF-16 codepoints.
Raises:
RuntimeError: If the gift info has no text.
"""
if not self.text:
raise RuntimeError("This GiftInfo has no 'text'.")
return parse_message_entities(self.text, self.entities, types)
class AcceptedGiftTypes(TelegramObject):
"""This object describes the types of gifts that can be gifted to a user or a chat.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal if their :attr:`unlimited_gifts`, :attr:`limited_gifts`,
:attr:`unique_gifts` and :attr:`premium_subscription` are equal.
.. versionadded:: 22.1
Args:
unlimited_gifts (:class:`bool`): :obj:`True`, if unlimited regular gifts are accepted.
limited_gifts (:class:`bool`): :obj:`True`, if limited regular gifts are accepted.
unique_gifts (:class:`bool`): :obj:`True`, if unique gifts or gifts that can be upgraded
to unique for free are accepted.
premium_subscription (:class:`bool`): :obj:`True`, if a Telegram Premium subscription
is accepted.
Attributes:
unlimited_gifts (:class:`bool`): :obj:`True`, if unlimited regular gifts are accepted.
limited_gifts (:class:`bool`): :obj:`True`, if limited regular gifts are accepted.
unique_gifts (:class:`bool`): :obj:`True`, if unique gifts or gifts that can be upgraded
to unique for free are accepted.
premium_subscription (:class:`bool`): :obj:`True`, if a Telegram Premium subscription
is accepted.
"""
__slots__ = (
"limited_gifts",
"premium_subscription",
"unique_gifts",
"unlimited_gifts",
)
def __init__(
self,
unlimited_gifts: bool,
limited_gifts: bool,
unique_gifts: bool,
premium_subscription: bool,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.unlimited_gifts: bool = unlimited_gifts
self.limited_gifts: bool = limited_gifts
self.unique_gifts: bool = unique_gifts
self.premium_subscription: bool = premium_subscription
self._id_attrs = (
self.unlimited_gifts,
self.limited_gifts,
self.unique_gifts,
self.premium_subscription,
)
self._freeze()
+91
View File
@@ -49,11 +49,13 @@ from telegram._forumtopic import (
GeneralForumTopicUnhidden,
)
from telegram._games.game import Game
from telegram._gifts import GiftInfo
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._linkpreviewoptions import LinkPreviewOptions
from telegram._messageautodeletetimerchanged import MessageAutoDeleteTimerChanged
from telegram._messageentity import MessageEntity
from telegram._paidmedia import PaidMediaInfo
from telegram._paidmessagepricechanged import PaidMessagePriceChanged
from telegram._passport.passportdata import PassportData
from telegram._payment.invoice import Invoice
from telegram._payment.refundedpayment import RefundedPayment
@@ -64,6 +66,7 @@ from telegram._reply import ReplyParameters
from telegram._shared import ChatShared, UsersShared
from telegram._story import Story
from telegram._telegramobject import TelegramObject
from telegram._uniquegift import UniqueGiftInfo
from telegram._user import User
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
@@ -443,6 +446,10 @@ class Message(MaybeInaccessibleMessage):
`More about Telegram Login >> <https://core.telegram.org/widgets/login>`_.
author_signature (:obj:`str`, optional): Signature of the post author for messages in
channels, or the custom title of an anonymous group administrator.
paid_star_count (:obj:`int`, optional): The number of Telegram Stars that were paid by the
sender of the message to send it
.. versionadded:: 22.1
passport_data (:class:`telegram.PassportData`, optional): Telegram Passport data.
poll (:class:`telegram.Poll`, optional): Message is a native poll,
information about the poll.
@@ -525,6 +532,14 @@ class Message(MaybeInaccessibleMessage):
with the bot.
.. versionadded:: 20.1
gift (:class:`telegram.GiftInfo`, optional): Service message: a regular gift was sent
or received.
.. versionadded:: 22.1
unique_gift (:class:`telegram.UniqueGiftInfo`, optional): Service message: a unique gift
was sent or received
.. versionadded:: 22.1
giveaway_created (:class:`telegram.GiveawayCreated`, optional): Service message: a
scheduled giveaway was created
@@ -541,6 +556,10 @@ class Message(MaybeInaccessibleMessage):
giveaway without public winners was completed
.. versionadded:: 20.8
paid_message_price_changed (:class:`telegram.PaidMessagePriceChanged`, optional): Service
message: the price for paid messages has changed in the chat
.. versionadded:: 22.1
external_reply (:class:`telegram.ExternalReplyInfo`, optional): Information about the
message that is being replied to, which may come from another chat or forum topic.
@@ -771,6 +790,10 @@ class Message(MaybeInaccessibleMessage):
`More about Telegram Login >> <https://core.telegram.org/widgets/login>`_.
author_signature (:obj:`str`): Optional. Signature of the post author for messages in
channels, or the custom title of an anonymous group administrator.
paid_star_count (:obj:`int`): Optional. The number of Telegram Stars that were paid by the
sender of the message to send it
.. versionadded:: 22.1
passport_data (:class:`telegram.PassportData`): Optional. Telegram Passport data.
Examples:
@@ -853,6 +876,14 @@ class Message(MaybeInaccessibleMessage):
with the bot.
.. versionadded:: 20.1
gift (:class:`telegram.GiftInfo`): Optional. Service message: a regular gift was sent
or received.
.. versionadded:: 22.1
unique_gift (:class:`telegram.UniqueGiftInfo`): Optional. Service message: a unique gift
was sent or received
.. versionadded:: 22.1
giveaway_created (:class:`telegram.GiveawayCreated`): Optional. Service message: a
scheduled giveaway was created
@@ -869,6 +900,10 @@ class Message(MaybeInaccessibleMessage):
giveaway without public winners was completed
.. versionadded:: 20.8
paid_message_price_changed (:class:`telegram.PaidMessagePriceChanged`): Optional. Service
message: the price for paid messages has changed in the chat
.. versionadded:: 22.1
external_reply (:class:`telegram.ExternalReplyInfo`): Optional. Information about the
message that is being replied to, which may come from another chat or forum topic.
@@ -966,6 +1001,7 @@ class Message(MaybeInaccessibleMessage):
"game",
"general_forum_topic_hidden",
"general_forum_topic_unhidden",
"gift",
"giveaway",
"giveaway_completed",
"giveaway_created",
@@ -989,6 +1025,8 @@ class Message(MaybeInaccessibleMessage):
"new_chat_photo",
"new_chat_title",
"paid_media",
"paid_message_price_changed",
"paid_star_count",
"passport_data",
"photo",
"pinned_message",
@@ -1008,6 +1046,7 @@ class Message(MaybeInaccessibleMessage):
"successful_payment",
"supergroup_chat_created",
"text",
"unique_gift",
"users_shared",
"venue",
"via_bot",
@@ -1109,6 +1148,10 @@ class Message(MaybeInaccessibleMessage):
show_caption_above_media: Optional[bool] = None,
paid_media: Optional[PaidMediaInfo] = None,
refunded_payment: Optional[RefundedPayment] = None,
gift: Optional[GiftInfo] = None,
unique_gift: Optional[UniqueGiftInfo] = None,
paid_message_price_changed: Optional[PaidMessagePriceChanged] = None,
paid_star_count: Optional[int] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
@@ -1212,6 +1255,12 @@ class Message(MaybeInaccessibleMessage):
self.show_caption_above_media: Optional[bool] = show_caption_above_media
self.paid_media: Optional[PaidMediaInfo] = paid_media
self.refunded_payment: Optional[RefundedPayment] = refunded_payment
self.gift: Optional[GiftInfo] = gift
self.unique_gift: Optional[UniqueGiftInfo] = unique_gift
self.paid_message_price_changed: Optional[PaidMessagePriceChanged] = (
paid_message_price_changed
)
self.paid_star_count: Optional[int] = paid_star_count
self._effective_attachment = DEFAULT_NONE
@@ -1346,6 +1395,11 @@ class Message(MaybeInaccessibleMessage):
data["refunded_payment"] = de_json_optional(
data.get("refunded_payment"), RefundedPayment, bot
)
data["gift"] = de_json_optional(data.get("gift"), GiftInfo, bot)
data["unique_gift"] = de_json_optional(data.get("unique_gift"), UniqueGiftInfo, bot)
data["paid_message_price_changed"] = de_json_optional(
data.get("paid_message_price_changed"), PaidMessagePriceChanged, bot
)
# Unfortunately, this needs to be here due to cyclic imports
from telegram._giveaway import ( # pylint: disable=import-outside-toplevel
@@ -4479,6 +4533,43 @@ class Message(MaybeInaccessibleMessage):
api_kwargs=api_kwargs,
)
async def read_business_message(
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.read_business_message(
chat_id=message.chat_id,
message_id=message.message_id,
business_connection_id=message.business_connection_id,
*args, **kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.read_business_message`.
.. versionadded:: 22.1
Returns:
:obj:`bool` On success, :obj:`True` is returned.
"""
return await self.get_bot().read_business_message(
chat_id=self.chat_id,
message_id=self.message_id,
business_connection_id=self.business_connection_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
def parse_entity(self, entity: MessageEntity) -> str:
"""Returns the text from a given :class:`telegram.MessageEntity`.
+419
View File
@@ -0,0 +1,419 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# 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
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains objects that represent owned gifts."""
import datetime as dtm
from collections.abc import Sequence
from typing import TYPE_CHECKING, Final, Optional
from telegram import constants
from telegram._gifts import Gift
from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject
from telegram._uniquegift import UniqueGift
from telegram._user import User
from telegram._utils import enum
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.entities import parse_message_entities, parse_message_entity
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class OwnedGift(TelegramObject):
"""This object describes a gift received and owned by a user or a chat. Currently, it
can be one of:
* :class:`telegram.OwnedGiftRegular`
* :class:`telegram.OwnedGiftUnique`
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`type` is equal.
.. versionadded:: 22.1
Args:
type (:obj:`str`): Type of the owned gift.
Attributes:
type (:obj:`str`): Type of the owned gift.
"""
__slots__ = ("type",)
REGULAR: Final[str] = constants.OwnedGiftType.REGULAR
""":const:`telegram.constants.OwnedGiftType.REGULAR`"""
UNIQUE: Final[str] = constants.OwnedGiftType.UNIQUE
""":const:`telegram.constants.OwnedGiftType.UNIQUE`"""
def __init__(
self,
type: str, # pylint: disable=redefined-builtin
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(api_kwargs=api_kwargs)
self.type: str = enum.get_member(constants.OwnedGiftType, type, type)
self._id_attrs = (self.type,)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "OwnedGift":
"""Converts JSON data to the appropriate :class:`OwnedGift` object, i.e. takes
care of selecting the correct subclass.
Args:
data (dict[:obj:`str`, ...]): The JSON data.
bot (:class:`telegram.Bot`, optional): The bot associated with this object.
Returns:
The Telegram object.
"""
data = cls._parse_data(data)
_class_mapping: dict[str, type[OwnedGift]] = {
cls.REGULAR: OwnedGiftRegular,
cls.UNIQUE: OwnedGiftUnique,
}
if cls is OwnedGift and data.get("type") in _class_mapping:
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
return super().de_json(data=data, bot=bot)
class OwnedGifts(TelegramObject):
"""Contains the list of gifts received and owned by a user or a chat.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`total_count` and :attr:`gifts` are equal.
.. versionadded:: 22.1
Args:
total_count (:obj:`int`): The total number of gifts owned by the user or the chat.
gifts (Sequence[:class:`telegram.OwnedGift`]): The list of gifts.
next_offset (:obj:`str`, optional): Offset for the next request. If empty,
then there are no more results.
Attributes:
total_count (:obj:`int`): The total number of gifts owned by the user or the chat.
gifts (Sequence[:class:`telegram.OwnedGift`]): The list of gifts.
next_offset (:obj:`str`): Optional. Offset for the next request. If empty,
then there are no more results.
"""
__slots__ = (
"gifts",
"next_offset",
"total_count",
)
def __init__(
self,
total_count: int,
gifts: Sequence[OwnedGift],
next_offset: Optional[str] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.total_count: int = total_count
self.gifts: tuple[OwnedGift, ...] = parse_sequence_arg(gifts)
self.next_offset: Optional[str] = next_offset
self._id_attrs = (self.total_count, self.gifts)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "OwnedGifts":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["gifts"] = de_list_optional(data.get("gifts"), OwnedGift, bot)
return super().de_json(data=data, bot=bot)
class OwnedGiftRegular(OwnedGift):
"""Describes a regular gift owned by a user or a chat.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`gift` and :attr:`send_date` are equal.
.. versionadded:: 22.1
Args:
gift (:class:`telegram.Gift`): Information about the regular gift.
owned_gift_id (:obj:`str`, optional): Unique identifier of the gift for the bot; for
gifts received on behalf of business accounts only.
sender_user (:class:`telegram.User`, optional): Sender of the gift if it is a known user.
send_date (:obj:`datetime.datetime`): Date the gift was sent as :class:`datetime.datetime`.
|datetime_localization|.
text (:obj:`str`, optional): Text of the message that was added to the gift.
entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities that
appear in the text.
is_private (:obj:`bool`, optional): :obj:`True`, if the sender and gift text are shown
only to the gift receiver; otherwise, everyone will be able to see them.
is_saved (:obj:`bool`, optional): :obj:`True`, if the gift is displayed on the account's
profile page; for gifts received on behalf of business accounts only.
can_be_upgraded (:obj:`bool`, optional): :obj:`True`, if the gift can be upgraded to a
unique gift; for gifts received on behalf of business accounts only.
was_refunded (:obj:`bool`, optional): :obj:`True`, if the gift was refunded and isn't
available anymore.
convert_star_count (:obj:`int`, optional): Number of Telegram Stars that can be
claimed by the receiver instead of the gift; omitted if the gift cannot be converted
to Telegram Stars.
prepaid_upgrade_star_count (:obj:`int`, optional): Number of Telegram Stars that were
paid by the sender for the ability to upgrade the gift.
Attributes:
type (:obj:`str`): Type of the gift, always :attr:`~telegram.OwnedGift.REGULAR`.
gift (:class:`telegram.Gift`): Information about the regular gift.
owned_gift_id (:obj:`str`): Optional. Unique identifier of the gift for the bot; for
gifts received on behalf of business accounts only.
sender_user (:class:`telegram.User`): Optional. Sender of the gift if it is a known user.
send_date (:obj:`datetime.datetime`): Date the gift was sent as :class:`datetime.datetime`.
|datetime_localization|.
text (:obj:`str`): Optional. Text of the message that was added to the gift.
entities (Sequence[:class:`telegram.MessageEntity`]): Optional. Special entities that
appear in the text.
is_private (:obj:`bool`): Optional. :obj:`True`, if the sender and gift text are shown
only to the gift receiver; otherwise, everyone will be able to see them.
is_saved (:obj:`bool`): Optional. :obj:`True`, if the gift is displayed on the account's
profile page; for gifts received on behalf of business accounts only.
can_be_upgraded (:obj:`bool`): Optional. :obj:`True`, if the gift can be upgraded to a
unique gift; for gifts received on behalf of business accounts only.
was_refunded (:obj:`bool`): Optional. :obj:`True`, if the gift was refunded and isn't
available anymore.
convert_star_count (:obj:`int`): Optional. Number of Telegram Stars that can be
claimed by the receiver instead of the gift; omitted if the gift cannot be converted
to Telegram Stars.
prepaid_upgrade_star_count (:obj:`int`): Optional. Number of Telegram Stars that were
paid by the sender for the ability to upgrade the gift.
"""
__slots__ = (
"can_be_upgraded",
"convert_star_count",
"entities",
"gift",
"is_private",
"is_saved",
"owned_gift_id",
"prepaid_upgrade_star_count",
"send_date",
"sender_user",
"text",
"was_refunded",
)
def __init__(
self,
gift: Gift,
send_date: dtm.datetime,
owned_gift_id: Optional[str] = None,
sender_user: Optional[User] = None,
text: Optional[str] = None,
entities: Optional[Sequence[MessageEntity]] = None,
is_private: Optional[bool] = None,
is_saved: Optional[bool] = None,
can_be_upgraded: Optional[bool] = None,
was_refunded: Optional[bool] = None,
convert_star_count: Optional[int] = None,
prepaid_upgrade_star_count: Optional[int] = None,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(type=OwnedGift.REGULAR, api_kwargs=api_kwargs)
with self._unfrozen():
self.gift: Gift = gift
self.send_date: dtm.datetime = send_date
self.owned_gift_id: Optional[str] = owned_gift_id
self.sender_user: Optional[User] = sender_user
self.text: Optional[str] = text
self.entities: tuple[MessageEntity, ...] = parse_sequence_arg(entities)
self.is_private: Optional[bool] = is_private
self.is_saved: Optional[bool] = is_saved
self.can_be_upgraded: Optional[bool] = can_be_upgraded
self.was_refunded: Optional[bool] = was_refunded
self.convert_star_count: Optional[int] = convert_star_count
self.prepaid_upgrade_star_count: Optional[int] = prepaid_upgrade_star_count
self._id_attrs = (self.type, self.gift, self.send_date)
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "OwnedGiftRegular":
"""See :meth:`telegram.OwnedGift.de_json`."""
data = cls._parse_data(data)
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["send_date"] = from_timestamp(data.get("send_date"), tzinfo=loc_tzinfo)
data["sender_user"] = de_json_optional(data.get("sender_user"), User, bot)
data["gift"] = de_json_optional(data.get("gift"), Gift, bot)
data["entities"] = de_list_optional(data.get("entities"), MessageEntity, bot)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
def parse_entity(self, entity: MessageEntity) -> str:
"""Returns the text in :attr:`text`
from a given :class:`telegram.MessageEntity` of :attr:`entities`.
Note:
This method is present because Telegram calculates the offset and length in
UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
(That is, you can't just slice ``OwnedGiftRegular.text`` with the offset and length.)
Args:
entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
be an entity that belongs to :attr:`entities`.
Returns:
:obj:`str`: The text of the given entity.
Raises:
RuntimeError: If the owned gift has no text.
"""
if not self.text:
raise RuntimeError("This OwnedGiftRegular has no 'text'.")
return parse_message_entity(self.text, entity)
def parse_entities(self, types: Optional[list[str]] = None) -> dict[MessageEntity, str]:
"""
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
It contains entities from this owned gift's text filtered by their ``type`` attribute as
the key, and the text that each entity belongs to as the value of the :obj:`dict`.
Note:
This method should always be used instead of the :attr:`entities`
attribute, since it calculates the correct substring from the message text based on
UTF-16 codepoints. See :attr:`parse_entity` for more info.
Args:
types (list[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the
``type`` attribute of an entity is contained in this list, it will be returned.
Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`.
Returns:
dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
the text that belongs to them, calculated based on UTF-16 codepoints.
Raises:
RuntimeError: If the owned gift has no text.
"""
if not self.text:
raise RuntimeError("This OwnedGiftRegular has no 'text'.")
return parse_message_entities(self.text, self.entities, types)
class OwnedGiftUnique(OwnedGift):
"""
Describes a unique gift received and owned by a user or a chat.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`gift` and :attr:`send_date` are equal.
.. versionadded:: 22.1
Args:
gift (:class:`telegram.UniqueGift`): Information about the unique gift.
owned_gift_id (:obj:`str`, optional): Unique identifier of the received gift for the
bot; for gifts received on behalf of business accounts only.
sender_user (:class:`telegram.User`, optional): Sender of the gift if it is a known user.
send_date (:obj:`datetime.datetime`): Date the gift was sent as :class:`datetime.datetime`.
|datetime_localization|.
is_saved (:obj:`bool`, optional): :obj:`True`, if the gift is displayed on the account's
profile page; for gifts received on behalf of business accounts only.
can_be_transferred (:obj:`bool`, optional): :obj:`True`, if the gift can be transferred to
another owner; for gifts received on behalf of business accounts only.
transfer_star_count (:obj:`int`, optional): Number of Telegram Stars that must be paid
to transfer the gift; omitted if the bot cannot transfer the gift.
Attributes:
type (:obj:`str`): Type of the owned gift, always :tg-const:`~telegram.OwnedGift.UNIQUE`.
gift (:class:`telegram.UniqueGift`): Information about the unique gift.
owned_gift_id (:obj:`str`): Optional. Unique identifier of the received gift for the
bot; for gifts received on behalf of business accounts only.
sender_user (:class:`telegram.User`): Optional. Sender of the gift if it is a known user.
send_date (:obj:`datetime.datetime`): Date the gift was sent as :class:`datetime.datetime`.
|datetime_localization|.
is_saved (:obj:`bool`): Optional. :obj:`True`, if the gift is displayed on the account's
profile page; for gifts received on behalf of business accounts only.
can_be_transferred (:obj:`bool`): Optional. :obj:`True`, if the gift can be transferred to
another owner; for gifts received on behalf of business accounts only.
transfer_star_count (:obj:`int`): Optional. Number of Telegram Stars that must be paid
to transfer the gift; omitted if the bot cannot transfer the gift.
"""
__slots__ = (
"can_be_transferred",
"gift",
"is_saved",
"owned_gift_id",
"send_date",
"sender_user",
"transfer_star_count",
)
def __init__(
self,
gift: UniqueGift,
send_date: dtm.datetime,
owned_gift_id: Optional[str] = None,
sender_user: Optional[User] = None,
is_saved: Optional[bool] = None,
can_be_transferred: Optional[bool] = None,
transfer_star_count: Optional[int] = None,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(type=OwnedGift.UNIQUE, api_kwargs=api_kwargs)
with self._unfrozen():
self.gift: UniqueGift = gift
self.send_date: dtm.datetime = send_date
self.owned_gift_id: Optional[str] = owned_gift_id
self.sender_user: Optional[User] = sender_user
self.is_saved: Optional[bool] = is_saved
self.can_be_transferred: Optional[bool] = can_be_transferred
self.transfer_star_count: Optional[int] = transfer_star_count
self._id_attrs = (self.type, self.gift, self.send_date)
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "OwnedGiftUnique":
"""See :meth:`telegram.OwnedGift.de_json`."""
data = cls._parse_data(data)
loc_tzinfo = extract_tzinfo_from_defaults(bot)
data["send_date"] = from_timestamp(data.get("send_date"), tzinfo=loc_tzinfo)
data["sender_user"] = de_json_optional(data.get("sender_user"), User, bot)
data["gift"] = de_json_optional(data.get("gift"), UniqueGift, bot)
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# 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
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that describes a price change of a paid message."""
from typing import Optional
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
class PaidMessagePriceChanged(TelegramObject):
"""Describes a service message about a change in the price of paid messages within a chat.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`paid_message_star_count` is equal.
.. versionadded:: 22.1
Args:
paid_message_star_count (:obj:`int`): The new number of Telegram Stars that must be paid by
non-administrator users of the supergroup chat for each sent message
Attributes:
paid_message_star_count (:obj:`int`): The new number of Telegram Stars that must be paid by
non-administrator users of the supergroup chat for each sent message
"""
__slots__ = ("paid_message_star_count",)
def __init__(
self,
paid_message_star_count: int,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(api_kwargs=api_kwargs)
self.paid_message_star_count: int = paid_message_star_count
self._id_attrs = (self.paid_message_star_count,)
self._freeze()
+6 -6
View File
@@ -48,10 +48,10 @@ class AffiliateInfo(TelegramObject):
amount (:obj:`int`): Integer amount of Telegram Stars received by the affiliate from the
transaction, rounded to 0; can be negative for refunds
nanostar_amount (:obj:`int`, optional): The number of
:tg-const:`~telegram.constants.StarTransactions.NANOSTAR_VALUE` shares of Telegram
:tg-const:`~telegram.constants.Nanostar.VALUE` shares of Telegram
Stars received by the affiliate; from
:tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MIN_AMOUNT` to
:tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT`;
:tg-const:`~telegram.constants.NanostarLimit.MIN_AMOUNT` to
:tg-const:`~telegram.constants.NanostarLimit.MAX_AMOUNT`;
can be negative for refunds
Attributes:
@@ -64,10 +64,10 @@ class AffiliateInfo(TelegramObject):
amount (:obj:`int`): Integer amount of Telegram Stars received by the affiliate from the
transaction, rounded to 0; can be negative for refunds
nanostar_amount (:obj:`int`): Optional. The number of
:tg-const:`~telegram.constants.StarTransactions.NANOSTAR_VALUE` shares of Telegram
:tg-const:`~telegram.constants.Nanostar.VALUE` shares of Telegram
Stars received by the affiliate; from
:tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MIN_AMOUNT` to
:tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT`;
:tg-const:`~telegram.constants.NanostarLimit.MIN_AMOUNT` to
:tg-const:`~telegram.constants.NanostarLimit.MAX_AMOUNT`;
can be negative for refunds
"""
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# 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
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
# pylint: disable=redefined-builtin
"""This module contains an object that represents a Telegram StarAmount."""
from typing import Optional
from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict
class StarAmount(TelegramObject):
"""Describes an amount of Telegram Stars.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`amount` and :attr:`nanostar_amount` are equal.
Args:
amount (:obj:`int`): Integer amount of Telegram Stars, rounded to ``0``; can be negative.
nanostar_amount (:obj:`int`, optional): The number of
:tg-const:`telegram.constants.Nanostar.VALUE` shares of Telegram
Stars; from :tg-const:`telegram.constants.NanostarLimit.MIN_AMOUNT`
to :tg-const:`telegram.constants.NanostarLimit.MAX_AMOUNT`; can be
negative if and only if :attr:`amount` is non-positive.
Attributes:
amount (:obj:`int`): Integer amount of Telegram Stars, rounded to ``0``; can be negative.
nanostar_amount (:obj:`int`): Optional. The number of
:tg-const:`telegram.constants.Nanostar.VALUE` shares of Telegram
Stars; from :tg-const:`telegram.constants.NanostarLimit.MIN_AMOUNT`
to :tg-const:`telegram.constants.NanostarLimit.MAX_AMOUNT`; can be
negative if and only if :attr:`amount` is non-positive.
"""
__slots__ = ("amount", "nanostar_amount")
def __init__(
self,
amount: int,
nanostar_amount: Optional[int] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.amount: int = amount
self.nanostar_amount: Optional[int] = nanostar_amount
self._id_attrs = (self.amount, self.nanostar_amount)
self._freeze()
+4 -4
View File
@@ -52,9 +52,9 @@ class StarTransaction(TelegramObject):
successful incoming payments from users.
amount (:obj:`int`): Integer amount of Telegram Stars transferred by the transaction.
nanostar_amount (:obj:`int`, optional): The number of
:tg-const:`~telegram.constants.StarTransactions.NANOSTAR_VALUE` shares of Telegram
:tg-const:`~telegram.constants.Nanostar.VALUE` shares of Telegram
Stars transferred by the transaction; from 0 to
:tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT`
:tg-const:`~telegram.constants.NanostarLimit.MAX_AMOUNT`
.. versionadded:: 21.9
date (:obj:`datetime.datetime`): Date the transaction was created as a datetime object.
@@ -72,9 +72,9 @@ class StarTransaction(TelegramObject):
successful incoming payments from users.
amount (:obj:`int`): Integer amount of Telegram Stars transferred by the transaction.
nanostar_amount (:obj:`int`): Optional. The number of
:tg-const:`~telegram.constants.StarTransactions.NANOSTAR_VALUE` shares of Telegram
:tg-const:`~telegram.constants.Nanostar.VALUE` shares of Telegram
Stars transferred by the transaction; from 0 to
:tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT`
:tg-const:`~telegram.constants.NanostarLimit.MAX_AMOUNT`
.. versionadded:: 21.9
date (:obj:`datetime.datetime`): Date the transaction was created as a datetime object.
+86 -14
View File
@@ -56,7 +56,7 @@ class TransactionPartner(TelegramObject):
.. versionadded:: 21.4
..versionchanged:: 21.11
.. versionchanged:: 21.11
Added :class:`TransactionPartnerChat`
Args:
@@ -281,55 +281,115 @@ class TransactionPartnerUser(TransactionPartner):
"""Describes a transaction with a user.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`user` are equal.
considered equal, if their :attr:`user` and :attr:`transaction_type` are equal.
.. versionadded:: 21.4
.. versionchanged:: 22.1
Equality comparison now includes the new required argument :paramref:`transaction_type`,
introduced in Bot API 9.0.
Args:
transaction_type (:obj:`str`): Type of the transaction, currently one of
:tg-const:`telegram.constants.TransactionPartnerUser.INVOICE_PAYMENT` for payments via
invoices, :tg-const:`telegram.constants.TransactionPartnerUser.PAID_MEDIA_PAYMENT`
for payments for paid media,
:tg-const:`telegram.constants.TransactionPartnerUser.GIFT_PURCHASE` for gifts sent by
the bot, :tg-const:`telegram.constants.TransactionPartnerUser.PREMIUM_PURCHASE`
for Telegram Premium subscriptions gifted by the bot,
:tg-const:`telegram.constants.TransactionPartnerUser.BUSINESS_ACCOUNT_TRANSFER` for
direct transfers from managed business accounts.
.. versionadded:: 22.1
user (:class:`telegram.User`): Information about the user.
affiliate (:class:`telegram.AffiliateInfo`, optional): Information about the affiliate that
received a commission via this transaction
received a commission via this transaction. Can be available only for
:tg-const:`telegram.constants.TransactionPartnerUser.INVOICE_PAYMENT`
and :tg-const:`telegram.constants.TransactionPartnerUser.PAID_MEDIA_PAYMENT`
transactions.
.. versionadded:: 21.9
invoice_payload (:obj:`str`, optional): Bot-specified invoice payload.
invoice_payload (:obj:`str`, optional): Bot-specified invoice payload. Can be available
only for :tg-const:`telegram.constants.TransactionPartnerUser.INVOICE_PAYMENT`
transactions.
subscription_period (:class:`datetime.timedelta`, optional): The duration of the paid
subscription
subscription. Can be available only for
:tg-const:`telegram.constants.TransactionPartnerUser.INVOICE_PAYMENT` transactions.
.. versionadded:: 21.8
paid_media (Sequence[:class:`telegram.PaidMedia`], optional): Information about the paid
media bought by the user.
media bought by the user. for
:tg-const:`telegram.constants.TransactionPartnerUser.PAID_MEDIA_PAYMENT`
transactions only.
.. versionadded:: 21.5
paid_media_payload (:obj:`str`, optional): Bot-specified paid media payload.
paid_media_payload (:obj:`str`, optional): Bot-specified paid media payload. Can be
available only for
:tg-const:`telegram.constants.TransactionPartnerUser.PAID_MEDIA_PAYMENT` transactions.
.. versionadded:: 21.6
gift (:class:`telegram.Gift`, optional): The gift sent to the user by the bot
gift (:class:`telegram.Gift`, optional): The gift sent to the user by the bot; for
:tg-const:`telegram.constants.TransactionPartnerUser.GIFT_PURCHASE` transactions only.
.. versionadded:: 21.8
premium_subscription_duration (:obj:`int`, optional): Number of months the gifted Telegram
Premium subscription will be active for; for
:tg-const:`telegram.constants.TransactionPartnerUser.PREMIUM_PURCHASE`
transactions only.
.. versionadded:: 22.1
Attributes:
type (:obj:`str`): The type of the transaction partner,
always :tg-const:`telegram.TransactionPartner.USER`.
transaction_type (:obj:`str`): Type of the transaction, currently one of
:tg-const:`telegram.constants.TransactionPartnerUser.INVOICE_PAYMENT` for payments via
invoices, :tg-const:`telegram.constants.TransactionPartnerUser.PAID_MEDIA_PAYMENT`
for payments for paid media,
:tg-const:`telegram.constants.TransactionPartnerUser.GIFT_PURCHASE` for gifts sent by
the bot, :tg-const:`telegram.constants.TransactionPartnerUser.PREMIUM_PURCHASE`
for Telegram Premium subscriptions gifted by the bot,
:tg-const:`telegram.constants.TransactionPartnerUser.BUSINESS_ACCOUNT_TRANSFER` for
direct transfers from managed business accounts.
.. versionadded:: 22.1
user (:class:`telegram.User`): Information about the user.
affiliate (:class:`telegram.AffiliateInfo`): Optional. Information about the affiliate that
received a commission via this transaction
received a commission via this transaction. Can be available only for
:tg-const:`telegram.constants.TransactionPartnerUser.INVOICE_PAYMENT`
and :tg-const:`telegram.constants.TransactionPartnerUser.PAID_MEDIA_PAYMENT`
transactions.
.. versionadded:: 21.9
invoice_payload (:obj:`str`): Optional. Bot-specified invoice payload.
invoice_payload (:obj:`str`): Optional. Bot-specified invoice payload. Can be available
only for :tg-const:`telegram.constants.TransactionPartnerUser.INVOICE_PAYMENT`
transactions.
subscription_period (:class:`datetime.timedelta`): Optional. The duration of the paid
subscription
subscription. Can be available only for
:tg-const:`telegram.constants.TransactionPartnerUser.INVOICE_PAYMENT` transactions.
.. versionadded:: 21.8
paid_media (tuple[:class:`telegram.PaidMedia`]): Optional. Information about the paid
media bought by the user.
media bought by the user. for
:tg-const:`telegram.constants.TransactionPartnerUser.PAID_MEDIA_PAYMENT`
transactions only.
.. versionadded:: 21.5
paid_media_payload (:obj:`str`): Optional. Bot-specified paid media payload.
paid_media_payload (:obj:`str`): Optional. Bot-specified paid media payload. Can be
available only for
:tg-const:`telegram.constants.TransactionPartnerUser.PAID_MEDIA_PAYMENT` transactions.
.. versionadded:: 21.6
gift (:class:`telegram.Gift`): Optional. The gift sent to the user by the bot
gift (:class:`telegram.Gift`): Optional. The gift sent to the user by the bot; for
:tg-const:`telegram.constants.TransactionPartnerUser.GIFT_PURCHASE` transactions only.
.. versionadded:: 21.8
premium_subscription_duration (:obj:`int`): Optional. Number of months the gifted Telegram
Premium subscription will be active for; for
:tg-const:`telegram.constants.TransactionPartnerUser.PREMIUM_PURCHASE`
transactions only.
.. versionadded:: 22.1
"""
@@ -339,7 +399,9 @@ class TransactionPartnerUser(TransactionPartner):
"invoice_payload",
"paid_media",
"paid_media_payload",
"premium_subscription_duration",
"subscription_period",
"transaction_type",
"user",
)
@@ -352,11 +414,18 @@ class TransactionPartnerUser(TransactionPartner):
subscription_period: Optional[dtm.timedelta] = None,
gift: Optional[Gift] = None,
affiliate: Optional[AffiliateInfo] = None,
premium_subscription_duration: Optional[int] = None,
# temporarily optional to account for changed signature
transaction_type: Optional[str] = None,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(type=TransactionPartner.USER, api_kwargs=api_kwargs)
# tags: deprecated 22.1, bot api 9.0
if transaction_type is None:
raise TypeError("`transaction_type` is a required argument since Bot API 9.0")
with self._unfrozen():
self.user: User = user
self.affiliate: Optional[AffiliateInfo] = affiliate
@@ -365,10 +434,13 @@ class TransactionPartnerUser(TransactionPartner):
self.paid_media_payload: Optional[str] = paid_media_payload
self.subscription_period: Optional[dtm.timedelta] = subscription_period
self.gift: Optional[Gift] = gift
self.premium_subscription_duration: Optional[int] = premium_subscription_duration
self.transaction_type: str = transaction_type
self._id_attrs = (
self.type,
self.user,
self.transaction_type,
)
@classmethod
+438
View File
@@ -0,0 +1,438 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# 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
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains objects that represent story areas."""
from typing import Final, Optional
from telegram import constants
from telegram._reaction import ReactionType
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.types import JSONDict
class StoryAreaPosition(TelegramObject):
"""Describes the position of a clickable area within a story.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if all of their attributes are equal.
.. versionadded:: 22.1
Args:
x_percentage (:obj:`float`): The abscissa of the area's center, as a percentage of the
media width.
y_percentage (:obj:`float`): The ordinate of the area's center, as a percentage of the
media height.
width_percentage (:obj:`float`): The width of the area's rectangle, as a percentage of the
media width.
height_percentage (:obj:`float`): The height of the area's rectangle, as a percentage of
the media height.
rotation_angle (:obj:`float`): The clockwise rotation angle of the rectangle, in degrees;
0-:tg-const:`~telegram.constants.StoryAreaPositionLimit.MAX_ROTATION_ANGLE`.
corner_radius_percentage (:obj:`float`): The radius of the rectangle corner rounding, as a
percentage of the media width.
Attributes:
x_percentage (:obj:`float`): The abscissa of the area's center, as a percentage of the
media width.
y_percentage (:obj:`float`): The ordinate of the area's center, as a percentage of the
media height.
width_percentage (:obj:`float`): The width of the area's rectangle, as a percentage of the
media width.
height_percentage (:obj:`float`): The height of the area's rectangle, as a percentage of
the media height.
rotation_angle (:obj:`float`): The clockwise rotation angle of the rectangle, in degrees;
0-:tg-const:`~telegram.constants.StoryAreaPositionLimit.MAX_ROTATION_ANGLE`.
corner_radius_percentage (:obj:`float`): The radius of the rectangle corner rounding, as a
percentage of the media width.
"""
__slots__ = (
"corner_radius_percentage",
"height_percentage",
"rotation_angle",
"width_percentage",
"x_percentage",
"y_percentage",
)
def __init__(
self,
x_percentage: float,
y_percentage: float,
width_percentage: float,
height_percentage: float,
rotation_angle: float,
corner_radius_percentage: float,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(api_kwargs=api_kwargs)
self.x_percentage: float = x_percentage
self.y_percentage: float = y_percentage
self.width_percentage: float = width_percentage
self.height_percentage: float = height_percentage
self.rotation_angle: float = rotation_angle
self.corner_radius_percentage: float = corner_radius_percentage
self._id_attrs = (
self.x_percentage,
self.y_percentage,
self.width_percentage,
self.height_percentage,
self.rotation_angle,
self.corner_radius_percentage,
)
self._freeze()
class LocationAddress(TelegramObject):
"""Describes the physical address of a location.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`country_code`, :attr:`state`, :attr:`city` and :attr:`street`
are equal.
.. versionadded:: 22.1
Args:
country_code (:obj:`str`): The two-letter ``ISO 3166-1 alpha-2`` country code of the
country where the location is located.
state (:obj:`str`, optional): State of the location.
city (:obj:`str`, optional): City of the location.
street (:obj:`str`, optional): Street address of the location.
Attributes:
country_code (:obj:`str`): The two-letter ``ISO 3166-1 alpha-2`` country code of the
country where the location is located.
state (:obj:`str`): Optional. State of the location.
city (:obj:`str`): Optional. City of the location.
street (:obj:`str`): Optional. Street address of the location.
"""
__slots__ = ("city", "country_code", "state", "street")
def __init__(
self,
country_code: str,
state: Optional[str] = None,
city: Optional[str] = None,
street: Optional[str] = None,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(api_kwargs=api_kwargs)
self.country_code: str = country_code
self.state: Optional[str] = state
self.city: Optional[str] = city
self.street: Optional[str] = street
self._id_attrs = (self.country_code, self.state, self.city, self.street)
self._freeze()
class StoryAreaType(TelegramObject):
"""Describes the type of a clickable area on a story. Currently, it can be one of:
* :class:`telegram.StoryAreaTypeLocation`
* :class:`telegram.StoryAreaTypeSuggestedReaction`
* :class:`telegram.StoryAreaTypeLink`
* :class:`telegram.StoryAreaTypeWeather`
* :class:`telegram.StoryAreaTypeUniqueGift`
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`type` is equal.
.. versionadded:: 22.1
Args:
type (:obj:`str`): Type of the area.
Attributes:
type (:obj:`str`): Type of the area.
"""
__slots__ = ("type",)
LOCATION: Final[str] = constants.StoryAreaTypeType.LOCATION
""":const:`telegram.constants.StoryAreaTypeType.LOCATION`"""
SUGGESTED_REACTION: Final[str] = constants.StoryAreaTypeType.SUGGESTED_REACTION
""":const:`telegram.constants.StoryAreaTypeType.SUGGESTED_REACTION`"""
LINK: Final[str] = constants.StoryAreaTypeType.LINK
""":const:`telegram.constants.StoryAreaTypeType.LINK`"""
WEATHER: Final[str] = constants.StoryAreaTypeType.WEATHER
""":const:`telegram.constants.StoryAreaTypeType.WEATHER`"""
UNIQUE_GIFT: Final[str] = constants.StoryAreaTypeType.UNIQUE_GIFT
""":const:`telegram.constants.StoryAreaTypeType.UNIQUE_GIFT`"""
def __init__(
self,
type: str, # pylint: disable=redefined-builtin
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(api_kwargs=api_kwargs)
self.type: str = enum.get_member(constants.StoryAreaTypeType, type, type)
self._id_attrs = (self.type,)
self._freeze()
class StoryAreaTypeLocation(StoryAreaType):
"""Describes a story area pointing to a location. Currently, a story can have up to
:tg-const:`~telegram.constants.StoryAreaTypeLimit.MAX_LOCATION_AREAS` location areas.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`latitude` and :attr:`longitude` are equal.
.. versionadded:: 22.1
Args:
latitude (:obj:`float`): Location latitude in degrees.
longitude (:obj:`float`): Location longitude in degrees.
address (:class:`telegram.LocationAddress`, optional): Address of the location.
Attributes:
type (:obj:`str`): Type of the area, always :attr:`~telegram.StoryAreaType.LOCATION`.
latitude (:obj:`float`): Location latitude in degrees.
longitude (:obj:`float`): Location longitude in degrees.
address (:class:`telegram.LocationAddress`): Optional. Address of the location.
"""
__slots__ = ("address", "latitude", "longitude")
def __init__(
self,
latitude: float,
longitude: float,
address: Optional[LocationAddress] = None,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(type=StoryAreaType.LOCATION, api_kwargs=api_kwargs)
with self._unfrozen():
self.latitude: float = latitude
self.longitude: float = longitude
self.address: Optional[LocationAddress] = address
self._id_attrs = (self.type, self.latitude, self.longitude)
class StoryAreaTypeSuggestedReaction(StoryAreaType):
"""
Describes a story area pointing to a suggested reaction. Currently, a story can have up to
:tg-const:`~telegram.constants.StoryAreaTypeLimit.MAX_SUGGESTED_REACTION_AREAS`
suggested reaction areas.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`reaction_type`, :attr:`is_dark` and :attr:`is_flipped`
are equal.
.. versionadded:: 22.1
Args:
reaction_type (:class:`ReactionType`): Type of the reaction.
is_dark (:obj:`bool`, optional): Pass :obj:`True` if the reaction area has a dark
background.
is_flipped (:obj:`bool`, optional): Pass :obj:`True` if reaction area corner is flipped.
Attributes:
type (:obj:`str`): Type of the area, always
:tg-const:`~telegram.StoryAreaType.SUGGESTED_REACTION`.
reaction_type (:class:`ReactionType`): Type of the reaction.
is_dark (:obj:`bool`): Optional. Pass :obj:`True` if the reaction area has a dark
background.
is_flipped (:obj:`bool`): Optional. Pass :obj:`True` if reaction area corner is flipped.
"""
__slots__ = ("is_dark", "is_flipped", "reaction_type")
def __init__(
self,
reaction_type: ReactionType,
is_dark: Optional[bool] = None,
is_flipped: Optional[bool] = None,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(type=StoryAreaType.SUGGESTED_REACTION, api_kwargs=api_kwargs)
with self._unfrozen():
self.reaction_type: ReactionType = reaction_type
self.is_dark: Optional[bool] = is_dark
self.is_flipped: Optional[bool] = is_flipped
self._id_attrs = (self.type, self.reaction_type, self.is_dark, self.is_flipped)
class StoryAreaTypeLink(StoryAreaType):
"""Describes a story area pointing to an ``HTTP`` or ``tg://`` link. Currently, a story can
have up to :tg-const:`~telegram.constants.StoryAreaTypeLimit.MAX_LINK_AREAS` link areas.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`url` is equal.
.. versionadded:: 22.1
Args:
url (:obj:`str`): ``HTTP`` or ``tg://`` URL to be opened when the area is clicked.
Attributes:
type (:obj:`str`): Type of the area, always :attr:`~telegram.StoryAreaType.LINK`.
url (:obj:`str`): ``HTTP`` or ``tg://`` URL to be opened when the area is clicked.
"""
__slots__ = ("url",)
def __init__(
self,
url: str,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(type=StoryAreaType.LINK, api_kwargs=api_kwargs)
with self._unfrozen():
self.url: str = url
self._id_attrs = (self.type, self.url)
class StoryAreaTypeWeather(StoryAreaType):
"""
Describes a story area containing weather information. Currently, a story can have up to
:tg-const:`~telegram.constants.StoryAreaTypeLimit.MAX_WEATHER_AREAS` weather areas.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`temperature`, :attr:`emoji` and
:attr:`background_color` are equal.
.. versionadded:: 22.1
Args:
temperature (:obj:`float`): Temperature, in degree Celsius.
emoji (:obj:`str`): Emoji representing the weather.
background_color (:obj:`int`): A color of the area background in the ``ARGB`` format.
Attributes:
type (:obj:`str`): Type of the area, always
:tg-const:`~telegram.StoryAreaType.WEATHER`.
temperature (:obj:`float`): Temperature, in degree Celsius.
emoji (:obj:`str`): Emoji representing the weather.
background_color (:obj:`int`): A color of the area background in the ``ARGB`` format.
"""
__slots__ = ("background_color", "emoji", "temperature")
def __init__(
self,
temperature: float,
emoji: str,
background_color: int,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(type=StoryAreaType.WEATHER, api_kwargs=api_kwargs)
with self._unfrozen():
self.temperature: float = temperature
self.emoji: str = emoji
self.background_color: int = background_color
self._id_attrs = (self.type, self.temperature, self.emoji, self.background_color)
class StoryAreaTypeUniqueGift(StoryAreaType):
"""
Describes a story area pointing to a unique gift. Currently, a story can have at most
:tg-const:`~telegram.constants.StoryAreaTypeLimit.MAX_UNIQUE_GIFT_AREAS` unique gift area.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`name` is equal.
.. versionadded:: 22.1
Args:
name (:obj:`str`): Unique name of the gift.
Attributes:
type (:obj:`str`): Type of the area, always
:tg-const:`~telegram.StoryAreaType.UNIQUE_GIFT`.
name (:obj:`str`): Unique name of the gift.
"""
__slots__ = ("name",)
def __init__(
self,
name: str,
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(type=StoryAreaType.UNIQUE_GIFT, api_kwargs=api_kwargs)
with self._unfrozen():
self.name: str = name
self._id_attrs = (self.type, self.name)
class StoryArea(TelegramObject):
"""Describes a clickable area on a story media.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`position` and :attr:`type` are equal.
.. versionadded:: 22.1
Args:
position (:class:`telegram.StoryAreaPosition`): Position of the area.
type (:class:`telegram.StoryAreaType`): Type of the area.
Attributes:
position (:class:`telegram.StoryAreaPosition`): Position of the area.
type (:class:`telegram.StoryAreaType`): Type of the area.
"""
__slots__ = ("position", "type")
def __init__(
self,
position: StoryAreaPosition,
type: StoryAreaType, # pylint: disable=redefined-builtin
*,
api_kwargs: Optional[JSONDict] = None,
) -> None:
super().__init__(api_kwargs=api_kwargs)
self.position: StoryAreaPosition = position
self.type: StoryAreaType = type
self._id_attrs = (self.position, self.type)
self._freeze()
+1 -1
View File
@@ -290,7 +290,7 @@ class TelegramObject:
self._bot = None
# get api_kwargs first because we may need to add entries to it (see try-except below)
api_kwargs = cast(dict[str, object], state.pop("api_kwargs", {}))
api_kwargs = cast("dict[str, object]", state.pop("api_kwargs", {}))
# get _frozen before the loop to avoid setting it to True in the loop
frozen = state.pop("_frozen", False)
+401
View File
@@ -0,0 +1,401 @@
#!/usr/bin/env python
#
#
# A library that provides a Python interface to the Telegram Bot API
# 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
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/]
"""This module contains classes related to unique gifs."""
from typing import TYPE_CHECKING, Final, Optional
from telegram import constants
from telegram._files.sticker import Sticker
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
class UniqueGiftModel(TelegramObject):
"""This object describes the model of a unique gift.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal if their :attr:`name`, :attr:`sticker` and :attr:`rarity_per_mille` are equal.
.. versionadded:: 22.1
Args:
name (:obj:`str`): Name of the model.
sticker (:class:`telegram.Sticker`): The sticker that represents the unique gift.
rarity_per_mille (:obj:`int`): The number of unique gifts that receive this
model for every ``1000`` gifts upgraded.
Attributes:
name (:obj:`str`): Name of the model.
sticker (:class:`telegram.Sticker`): The sticker that represents the unique gift.
rarity_per_mille (:obj:`int`): The number of unique gifts that receive this
model for every ``1000`` gifts upgraded.
"""
__slots__ = (
"name",
"rarity_per_mille",
"sticker",
)
def __init__(
self,
name: str,
sticker: Sticker,
rarity_per_mille: int,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.name: str = name
self.sticker: Sticker = sticker
self.rarity_per_mille: int = rarity_per_mille
self._id_attrs = (self.name, self.sticker, self.rarity_per_mille)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "UniqueGiftModel":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["sticker"] = de_json_optional(data.get("sticker"), Sticker, bot)
return super().de_json(data=data, bot=bot)
class UniqueGiftSymbol(TelegramObject):
"""This object describes the symbol shown on the pattern of a unique gift.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal if their :attr:`name`, :attr:`sticker` and :attr:`rarity_per_mille` are equal.
.. versionadded:: 22.1
Args:
name (:obj:`str`): Name of the symbol.
sticker (:class:`telegram.Sticker`): The sticker that represents the unique gift.
rarity_per_mille (:obj:`int`): The number of unique gifts that receive this
model for every ``1000`` gifts upgraded.
Attributes:
name (:obj:`str`): Name of the symbol.
sticker (:class:`telegram.Sticker`): The sticker that represents the unique gift.
rarity_per_mille (:obj:`int`): The number of unique gifts that receive this
model for every ``1000`` gifts upgraded.
"""
__slots__ = (
"name",
"rarity_per_mille",
"sticker",
)
def __init__(
self,
name: str,
sticker: Sticker,
rarity_per_mille: int,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.name: str = name
self.sticker: Sticker = sticker
self.rarity_per_mille: int = rarity_per_mille
self._id_attrs = (self.name, self.sticker, self.rarity_per_mille)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "UniqueGiftSymbol":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["sticker"] = de_json_optional(data.get("sticker"), Sticker, bot)
return super().de_json(data=data, bot=bot)
class UniqueGiftBackdropColors(TelegramObject):
"""This object describes the colors of the backdrop of a unique gift.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal if their :attr:`center_color`, :attr:`edge_color`, :attr:`symbol_color`,
and :attr:`text_color` are equal.
.. versionadded:: 22.1
Args:
center_color (:obj:`int`): The color in the center of the backdrop in RGB format.
edge_color (:obj:`int`): The color on the edges of the backdrop in RGB format.
symbol_color (:obj:`int`): The color to be applied to the symbol in RGB format.
text_color (:obj:`int`): The color for the text on the backdrop in RGB format.
Attributes:
center_color (:obj:`int`): The color in the center of the backdrop in RGB format.
edge_color (:obj:`int`): The color on the edges of the backdrop in RGB format.
symbol_color (:obj:`int`): The color to be applied to the symbol in RGB format.
text_color (:obj:`int`): The color for the text on the backdrop in RGB format.
"""
__slots__ = (
"center_color",
"edge_color",
"symbol_color",
"text_color",
)
def __init__(
self,
center_color: int,
edge_color: int,
symbol_color: int,
text_color: int,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.center_color: int = center_color
self.edge_color: int = edge_color
self.symbol_color: int = symbol_color
self.text_color: int = text_color
self._id_attrs = (self.center_color, self.edge_color, self.symbol_color, self.text_color)
self._freeze()
class UniqueGiftBackdrop(TelegramObject):
"""This object describes the backdrop of a unique gift.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal if their :attr:`name`, :attr:`colors`, and :attr:`rarity_per_mille` are equal.
.. versionadded:: 22.1
Args:
name (:obj:`str`): Name of the backdrop.
colors (:class:`telegram.UniqueGiftBackdropColors`): Colors of the backdrop.
rarity_per_mille (:obj:`int`): The number of unique gifts that receive this backdrop
for every ``1000`` gifts upgraded.
Attributes:
name (:obj:`str`): Name of the backdrop.
colors (:class:`telegram.UniqueGiftBackdropColors`): Colors of the backdrop.
rarity_per_mille (:obj:`int`): The number of unique gifts that receive this backdrop
for every ``1000`` gifts upgraded.
"""
__slots__ = (
"colors",
"name",
"rarity_per_mille",
)
def __init__(
self,
name: str,
colors: UniqueGiftBackdropColors,
rarity_per_mille: int,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.name: str = name
self.colors: UniqueGiftBackdropColors = colors
self.rarity_per_mille: int = rarity_per_mille
self._id_attrs = (self.name, self.colors, self.rarity_per_mille)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "UniqueGiftBackdrop":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["colors"] = de_json_optional(data.get("colors"), UniqueGiftBackdropColors, bot)
return super().de_json(data=data, bot=bot)
class UniqueGift(TelegramObject):
"""This object describes a unique gift that was upgraded from a regular gift.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal if their :attr:`base_name`, :attr:`name`, :attr:`number`, :class:`model`,
:attr:`symbol`, and :attr:`backdrop` are equal.
.. versionadded:: 22.1
Args:
base_name (:obj:`str`): Human-readable name of the regular gift from which this unique
gift was upgraded.
name (:obj:`str`): Unique name of the gift. This name can be used
in ``https://t.me/nft/...`` links and story areas.
number (:obj:`int`): Unique number of the upgraded gift among gifts upgraded from the
same regular gift.
model (:class:`UniqueGiftModel`): Model of the gift.
symbol (:class:`UniqueGiftSymbol`): Symbol of the gift.
backdrop (:class:`UniqueGiftBackdrop`): Backdrop of the gift.
Attributes:
base_name (:obj:`str`): Human-readable name of the regular gift from which this unique
gift was upgraded.
name (:obj:`str`): Unique name of the gift. This name can be used
in ``https://t.me/nft/...`` links and story areas.
number (:obj:`int`): Unique number of the upgraded gift among gifts upgraded from the
same regular gift.
model (:class:`telegram.UniqueGiftModel`): Model of the gift.
symbol (:class:`telegram.UniqueGiftSymbol`): Symbol of the gift.
backdrop (:class:`telegram.UniqueGiftBackdrop`): Backdrop of the gift.
"""
__slots__ = (
"backdrop",
"base_name",
"model",
"name",
"number",
"symbol",
)
def __init__(
self,
base_name: str,
name: str,
number: int,
model: UniqueGiftModel,
symbol: UniqueGiftSymbol,
backdrop: UniqueGiftBackdrop,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.base_name: str = base_name
self.name: str = name
self.number: int = number
self.model: UniqueGiftModel = model
self.symbol: UniqueGiftSymbol = symbol
self.backdrop: UniqueGiftBackdrop = backdrop
self._id_attrs = (
self.base_name,
self.name,
self.number,
self.model,
self.symbol,
self.backdrop,
)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "UniqueGift":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["model"] = de_json_optional(data.get("model"), UniqueGiftModel, bot)
data["symbol"] = de_json_optional(data.get("symbol"), UniqueGiftSymbol, bot)
data["backdrop"] = de_json_optional(data.get("backdrop"), UniqueGiftBackdrop, bot)
return super().de_json(data=data, bot=bot)
class UniqueGiftInfo(TelegramObject):
"""Describes a service message about a unique gift that was sent or received.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal if their :attr:`gift`, and :attr:`origin` are equal.
.. versionadded:: 22.1
Args:
gift (:class:`UniqueGift`): Information about the gift.
origin (:obj:`str`): Origin of the gift. Currently, either :attr:`UPGRADE`
or :attr:`TRANSFER`.
owned_gift_id (:obj:`str`, optional) Unique identifier of the received gift for the
bot; only present for gifts received on behalf of business accounts.
transfer_star_count (:obj:`int`, optional): Number of Telegram Stars that must be paid
to transfer the gift; omitted if the bot cannot transfer the gift.
Attributes:
gift (:class:`UniqueGift`): Information about the gift.
origin (:obj:`str`): Origin of the gift. Currently, either :attr:`UPGRADE`
or :attr:`TRANSFER`.
owned_gift_id (:obj:`str`) Optional. Unique identifier of the received gift for the
bot; only present for gifts received on behalf of business accounts.
transfer_star_count (:obj:`int`): Optional. Number of Telegram Stars that must be paid
to transfer the gift; omitted if the bot cannot transfer the gift.
"""
UPGRADE: Final[str] = constants.UniqueGiftInfoOrigin.UPGRADE
""":const:`telegram.constants.UniqueGiftInfoOrigin.UPGRADE`"""
TRANSFER: Final[str] = constants.UniqueGiftInfoOrigin.TRANSFER
""":const:`telegram.constants.UniqueGiftInfoOrigin.TRANSFER`"""
__slots__ = (
"gift",
"origin",
"owned_gift_id",
"transfer_star_count",
)
def __init__(
self,
gift: UniqueGift,
origin: str,
owned_gift_id: Optional[str] = None,
transfer_star_count: Optional[int] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.gift: UniqueGift = gift
self.origin: str = enum.get_member(constants.UniqueGiftInfoOrigin, origin, origin)
# Optional
self.owned_gift_id: Optional[str] = owned_gift_id
self.transfer_star_count: Optional[int] = transfer_star_count
self._id_attrs = (self.gift, self.origin)
self._freeze()
@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "UniqueGiftInfo":
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
data["gift"] = de_json_optional(data.get("gift"), UniqueGift, bot)
return super().de_json(data=data, bot=bot)
+43
View File
@@ -247,6 +247,9 @@ class User(TelegramObject):
For the documentation of the arguments, please see
:meth:`telegram.Bot.get_user_profile_photos`.
Returns:
:class:`telegram.UserProfilePhotos`
"""
return await self.get_bot().get_user_profile_photos(
user_id=self.id,
@@ -1698,6 +1701,46 @@ class User(TelegramObject):
api_kwargs=api_kwargs,
)
async def gift_premium_subscription(
self,
month_count: int,
star_count: int,
text: Optional[str] = None,
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
text_entities: Optional[Sequence["MessageEntity"]] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: Optional[JSONDict] = None,
) -> bool:
"""Shortcut for::
await bot.gift_premium_subscription(user_id=update.effective_user.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.gift_premium_subscription`.
.. versionadded:: 22.1
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().gift_premium_subscription(
user_id=self.id,
month_count=month_count,
star_count=star_count,
text=text,
text_parse_mode=text_parse_mode,
text_entities=text_entities,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def send_copy(
self,
from_chat_id: Union[str, int],

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