mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2025-01-04 18:12:12 +01:00
Merge branch 'refs/heads/master' into overhaul-tests
# Conflicts: # tests/test_bot.py
This commit is contained in:
commit
9fe518f023
93 changed files with 2073 additions and 2018 deletions
11
.github/CONTRIBUTING.rst
vendored
11
.github/CONTRIBUTING.rst
vendored
|
@ -26,7 +26,7 @@ Setting things up
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install -r requirements-all.txt
|
||||
$ pip install -r requirements-dev-all.txt
|
||||
|
||||
|
||||
5. Install pre-commit hooks:
|
||||
|
@ -210,13 +210,8 @@ doc strings don't have a separate documentation site they generate, instead, the
|
|||
|
||||
User facing documentation
|
||||
-------------------------
|
||||
We use `sphinx`_ to generate static HTML docs. To build them, first make sure you're running Python 3.9 or above and have the required dependencies:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install -r docs/requirements-docs.txt
|
||||
|
||||
then run the following from the PTB root directory:
|
||||
We use `sphinx`_ to generate static HTML docs. To build them, first make sure you're running Python 3.9 or above and have the required dependencies installed as explained above.
|
||||
Then, run the following from the PTB root directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
|
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
|
@ -28,7 +28,7 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: |
|
||||
python -W ignore -m pip install --upgrade pip
|
||||
python -W ignore -m pip install -r requirements-all.txt
|
||||
python -W ignore -m pip install -r requirements-dev-all.txt
|
||||
- name: Test autogeneration of admonitions
|
||||
run: pytest -v --tb=short tests/docs/admonition_inserter.py
|
||||
- name: Build docs
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
name: Warning maintainers
|
||||
on:
|
||||
pull_request_target:
|
||||
paths:
|
||||
- requirements.txt
|
||||
- requirements-opts.txt
|
||||
- .pre-commit-config.yaml
|
||||
permissions:
|
||||
pull-requests: write
|
||||
jobs:
|
||||
job:
|
||||
runs-on: ubuntu-latest
|
||||
name: about pre-commit and dependency change
|
||||
steps:
|
||||
- name: running the check
|
||||
uses: Poolitzer/notifier-action@master
|
||||
with:
|
||||
notify-message: Hey! Looks like you edited the (optional) requirements or the pre-commit hooks. I'm just a friendly reminder to keep the additional dependencies for the hooks in sync with the requirements :)
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
18
.github/workflows/readme_notifier.yml
vendored
18
.github/workflows/readme_notifier.yml
vendored
|
@ -1,18 +0,0 @@
|
|||
name: Warning maintainers
|
||||
on:
|
||||
pull_request_target:
|
||||
paths:
|
||||
- README.rst
|
||||
- README_RAW.rst
|
||||
permissions:
|
||||
pull-requests: write
|
||||
jobs:
|
||||
job:
|
||||
runs-on: ubuntu-latest
|
||||
name: about readme change
|
||||
steps:
|
||||
- name: running the check
|
||||
uses: Poolitzer/notifier-action@master
|
||||
with:
|
||||
notify-message: Hey! Looks like you edited README.rst or README_RAW.rst. I'm just a friendly reminder to apply relevant changes to both of those files :)
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
5
.github/workflows/test_official.yml
vendored
5
.github/workflows/test_official.yml
vendored
|
@ -29,9 +29,8 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: |
|
||||
python -W ignore -m pip install --upgrade pip
|
||||
python -W ignore -m pip install -r requirements.txt
|
||||
python -W ignore -m pip install -r requirements-opts.txt
|
||||
python -W ignore -m pip install -r requirements-dev.txt
|
||||
python -W ignore -m pip install .[all]
|
||||
python -W ignore -m pip install -r requirements-unit-tests.txt
|
||||
- name: Compare to official api
|
||||
run: |
|
||||
pytest -v tests/test_official/test_official.py --junit-xml=.test_report_official.xml
|
||||
|
|
7
.github/workflows/type_completeness.yml
vendored
7
.github/workflows/type_completeness.yml
vendored
|
@ -3,8 +3,7 @@ on:
|
|||
pull_request:
|
||||
paths:
|
||||
- telegram/**
|
||||
- requirements.txt
|
||||
- requirements-opts.txt
|
||||
- pyproject.toml
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
@ -19,12 +18,12 @@ jobs:
|
|||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.9
|
||||
python-version: 3.12
|
||||
cache: 'pip'
|
||||
cache-dependency-path: '**/requirements*.txt'
|
||||
- name: Install Pyright
|
||||
run: |
|
||||
python -W ignore -m pip install pyright~=1.1.316
|
||||
python -W ignore -m pip install pyright~=1.1.367
|
||||
- name: Get PR Completeness
|
||||
# Must run before base completeness, as base completeness will checkout the base branch
|
||||
# And we can't go back to the PR branch after that in case the PR is coming from a fork
|
||||
|
|
13
.github/workflows/unit_tests.yml
vendored
13
.github/workflows/unit_tests.yml
vendored
|
@ -4,9 +4,8 @@ on:
|
|||
paths:
|
||||
- telegram/**
|
||||
- tests/**
|
||||
- requirements.txt
|
||||
- requirements-opts.txt
|
||||
- requirements-dev.txt
|
||||
- pyproject.toml
|
||||
- requirements-unit-tests.txt
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
@ -20,7 +19,7 @@ jobs:
|
|||
runs-on: ${{matrix.os}}
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
|
||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13.0-beta.2']
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
|
@ -35,8 +34,8 @@ jobs:
|
|||
run: |
|
||||
python -W ignore -m pip install --upgrade pip
|
||||
python -W ignore -m pip install -U pytest-cov
|
||||
python -W ignore -m pip install -r requirements.txt
|
||||
python -W ignore -m pip install -r requirements-dev.txt
|
||||
python -W ignore -m pip install .
|
||||
python -W ignore -m pip install -r requirements-unit-tests.txt
|
||||
python -W ignore -m pip install pytest-xdist[psutil]
|
||||
|
||||
- name: Test with pytest
|
||||
|
@ -65,7 +64,7 @@ jobs:
|
|||
|
||||
# Test the rest
|
||||
export TEST_WITH_OPT_DEPS='true'
|
||||
pip install -r requirements-opts.txt
|
||||
pip install .[all]
|
||||
# `-n auto --dist loadfile` uses pytest-xdist to run each test file on a different CPU
|
||||
# worker. Increasing number of workers has little effect on test duration, but it seems
|
||||
# to increase flakyness, specially on python 3.7 with --dist=loadgroup.
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -92,3 +92,6 @@ telegram.jpg
|
|||
|
||||
# virtual env
|
||||
venv*
|
||||
|
||||
# environment manager:
|
||||
.mise.toml
|
|
@ -1,4 +1,4 @@
|
|||
# Make sure that the additional_dependencies here match requirements(-opts).txt
|
||||
# Make sure that the additional_dependencies here match pyproject.toml
|
||||
|
||||
ci:
|
||||
autofix_prs: false
|
||||
|
|
34
CHANGES.rst
34
CHANGES.rst
|
@ -4,6 +4,40 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
Version 21.3
|
||||
============
|
||||
*Released 2024-06-07*
|
||||
|
||||
This is the technical changelog for version 21.3. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Major Changes
|
||||
-------------
|
||||
|
||||
- Full Support for Bot API 7.4 (:pr:`4286`, :pr:`4276` closes :issue:`4275`, :pr:`4285`, :pr:`4283`, :pr:`4280`, :pr:`4278`, :pr:`4279`)
|
||||
- Deprecate ``python-telegram-bot-raw`` (:pr:`4270`)
|
||||
- Remove Functionality Deprecated in Bot API 7.3 (:pr:`4266` closes :issue:`4244`)
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
- Add Parameter ``chat_id`` to ``ChatMemberHandler`` (:pr:`4290` by `uniquetrij <https://github.com/uniquetrij>`_ closes :issue:`4287`)
|
||||
|
||||
Documentation Improvements
|
||||
--------------------------
|
||||
|
||||
- Documentation Improvements (:pr:`4264` closes :issue:`4240`)
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Add ``setuptools`` to ``requirements-dev.txt`` (:pr:`4282`)
|
||||
- Update Settings for pre-commit.ci (:pr:`4265`)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- Bump ``pytest`` from 8.2.0 to 8.2.1 (:pr:`4272`)
|
||||
|
||||
Version 21.2
|
||||
============
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
include LICENSE LICENSE.lesser requirements.txt requirements-opts.txt README_RAW.rst telegram/py.typed
|
17
README.rst
17
README.rst
|
@ -1,6 +1,3 @@
|
|||
..
|
||||
Make sure to apply any changes to this file to README_RAW.rst as well!
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/python-telegram-bot/logos/master/logo-text/png/ptb-logo-text_768.png
|
||||
:align: center
|
||||
:target: https://python-telegram-bot.org
|
||||
|
@ -14,7 +11,7 @@
|
|||
:target: https://pypi.org/project/python-telegram-bot/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.3-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.4-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API version
|
||||
|
||||
|
@ -79,17 +76,10 @@ In addition to the pure API implementation, this library features a number of hi
|
|||
make the development of bots easy and straightforward. These classes are contained in the
|
||||
``telegram.ext`` submodule.
|
||||
|
||||
A pure API implementation *without* ``telegram.ext`` is available as the standalone package ``python-telegram-bot-raw``. `See here for details. <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/README_RAW.rst>`_
|
||||
|
||||
Note
|
||||
----
|
||||
|
||||
Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conjunction will result in undesired side-effects, so only install *one* of both.
|
||||
|
||||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **7.3** are supported.
|
||||
All types and methods of the Telegram Bot API **7.4** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
@ -108,7 +98,8 @@ You can also install ``python-telegram-bot`` from source, though this is usually
|
|||
|
||||
$ git clone https://github.com/python-telegram-bot/python-telegram-bot
|
||||
$ cd python-telegram-bot
|
||||
$ python setup.py install
|
||||
$ pip install build
|
||||
$ python -m build
|
||||
|
||||
Verifying Releases
|
||||
------------------
|
||||
|
|
206
README_RAW.rst
206
README_RAW.rst
|
@ -1,206 +0,0 @@
|
|||
..
|
||||
Make sure to apply any changes to this file to README.rst as well!
|
||||
|
||||
.. image:: https://github.com/python-telegram-bot/logos/blob/master/logo-text/png/ptb-raw-logo-text_768.png?raw=true
|
||||
:align: center
|
||||
:target: https://python-telegram-bot.org
|
||||
:alt: python-telegram-bot-raw Logo
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/python-telegram-bot-raw.svg
|
||||
:target: https://pypi.org/project/python-telegram-bot-raw/
|
||||
:alt: PyPi Package Version
|
||||
|
||||
.. image:: https://img.shields.io/pypi/pyversions/python-telegram-bot-raw.svg
|
||||
:target: https://pypi.org/project/python-telegram-bot-raw/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.3-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API version
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/python-telegram-bot-raw
|
||||
:target: https://pypistats.org/packages/python-telegram-bot-raw
|
||||
:alt: PyPi Package Monthly Download
|
||||
|
||||
.. image:: https://readthedocs.org/projects/python-telegram-bot/badge/?version=stable
|
||||
:target: https://docs.python-telegram-bot.org/
|
||||
:alt: Documentation Status
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/python-telegram-bot-raw.svg
|
||||
:target: https://www.gnu.org/licenses/lgpl-3.0.html
|
||||
:alt: LGPLv3 License
|
||||
|
||||
.. image:: https://github.com/python-telegram-bot/python-telegram-bot/actions/workflows/unit_tests.yml/badge.svg?branch=master
|
||||
:target: https://github.com/python-telegram-bot/python-telegram-bot/
|
||||
:alt: Github Actions workflow
|
||||
|
||||
.. image:: https://codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg
|
||||
:target: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot
|
||||
:alt: Code coverage
|
||||
|
||||
.. image:: https://isitmaintained.com/badge/resolution/python-telegram-bot/python-telegram-bot.svg
|
||||
:target: https://isitmaintained.com/project/python-telegram-bot/python-telegram-bot
|
||||
:alt: Median time to resolve an issue
|
||||
|
||||
.. image:: https://api.codacy.com/project/badge/Grade/99d901eaa09b44b4819aec05c330c968
|
||||
:target: https://app.codacy.com/gh/python-telegram-bot/python-telegram-bot/dashboard
|
||||
:alt: Code quality: Codacy
|
||||
|
||||
.. image:: https://results.pre-commit.ci/badge/github/python-telegram-bot/python-telegram-bot/master.svg
|
||||
:target: https://results.pre-commit.ci/latest/github/python-telegram-bot/python-telegram-bot/master
|
||||
:alt: pre-commit.ci status
|
||||
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/psf/black
|
||||
:alt: Code Style: Black
|
||||
|
||||
.. image:: https://img.shields.io/badge/Telegram-Channel-blue.svg?logo=telegram
|
||||
:target: https://t.me/pythontelegrambotchannel
|
||||
:alt: Telegram Channel
|
||||
|
||||
.. image:: https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram
|
||||
:target: https://telegram.me/pythontelegrambotgroup
|
||||
:alt: Telegram Group
|
||||
|
||||
We have made you a wrapper you can't refuse
|
||||
|
||||
We have a vibrant community of developers helping each other in our `Telegram group <https://telegram.me/pythontelegrambotgroup>`_. Join us!
|
||||
|
||||
*Stay tuned for library updates and new releases on our* `Telegram Channel <https://telegram.me/pythontelegrambotchannel>`_.
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This library provides a pure Python, asynchronous interface for the
|
||||
`Telegram Bot API <https://core.telegram.org/bots/api>`_.
|
||||
It's compatible with Python versions **3.8+**.
|
||||
|
||||
``python-telegram-bot-raw`` is part of the `python-telegram-bot <https://python-telegram-bot.org>`_ ecosystem and provides the pure API functionality extracted from PTB. It therefore does not have independent release schedules, changelogs or documentation.
|
||||
|
||||
Note
|
||||
----
|
||||
|
||||
Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conjunction will result in undesired side-effects, so only install *one* of both.
|
||||
|
||||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **7.3** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
||||
You can install or upgrade ``python-telegram-bot`` via
|
||||
|
||||
.. code:: shell
|
||||
|
||||
$ pip install python-telegram-bot-raw --upgrade
|
||||
|
||||
To install a pre-release, use the ``--pre`` `flag <https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-pre>`_ in addition.
|
||||
|
||||
You can also install ``python-telegram-bot-raw`` from source, though this is usually not necessary.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
$ git clone https://github.com/python-telegram-bot/python-telegram-bot
|
||||
$ cd python-telegram-bot
|
||||
$ python setup_raw.py install
|
||||
|
||||
Note
|
||||
----
|
||||
|
||||
Installing the ``.tar.gz`` archive available on PyPi directly via ``pip`` will *not* work as expected, as ``pip`` does not recognize that it should use ``setup_raw.py`` instead of ``setup.py``.
|
||||
|
||||
Verifying Releases
|
||||
------------------
|
||||
|
||||
We sign all the releases with a GPG key.
|
||||
The signatures are uploaded to both the `GitHub releases page <https://github.com/python-telegram-bot/python-telegram-bot/releases>`_ and the `PyPI project <https://pypi.org/project/python-telegram-bot/>`_ and end with a suffix ``.asc``.
|
||||
Please find the public keys `here <https://github.com/python-telegram-bot/python-telegram-bot/tree/master/public_keys>`_.
|
||||
The keys are named in the format ``<first_version>-<last_version>.gpg`` or ``<first_version>-current.gpg`` if the key is currently being used for new releases.
|
||||
|
||||
In addition, the GitHub release page also contains the sha1 hashes of the release files in the files with the suffix ``.sha1``.
|
||||
|
||||
This allows you to verify that a release file that you downloaded was indeed provided by the ``python-telegram-bot`` team.
|
||||
|
||||
Dependencies & Their Versions
|
||||
-----------------------------
|
||||
|
||||
``python-telegram-bot`` tries to use as few 3rd party dependencies as possible.
|
||||
However, for some features using a 3rd party library is more sane than implementing the functionality again.
|
||||
As these features are *optional*, the corresponding 3rd party dependencies are not installed by default.
|
||||
Instead, they are listed as optional dependencies.
|
||||
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
|
||||
|
||||
The only required dependency is `httpx ~= 0.27 <https://www.python-httpx.org>`_ for
|
||||
``telegram.request.HTTPXRequest``, the default networking backend.
|
||||
|
||||
``python-telegram-bot`` is most useful when used along with additional libraries.
|
||||
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the (optional) dependencies.
|
||||
On the other hand, we have to ensure stability of ``python-telegram-bot``, which is why we do apply version bounds.
|
||||
If you encounter dependency conflicts due to these bounds, feel free to reach out.
|
||||
|
||||
Optional Dependencies
|
||||
#####################
|
||||
|
||||
PTB can be installed with optional dependencies:
|
||||
|
||||
* ``pip install "python-telegram-bot-raw[passport]"`` installs the `cryptography>=39.0.1 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
|
||||
* ``pip install "python-telegram-bot-raw[socks]"`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
|
||||
* ``pip install "python-telegram-bot-raw[http2]"`` installs `httpx[http2] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to use HTTP/2.
|
||||
|
||||
To install multiple optional dependencies, separate them by commas, e.g. ``pip install "python-telegram-bot-raw[passport,socks]"``.
|
||||
|
||||
Additionally, the shortcut ``pip install "python-telegram-bot-raw[all]"`` installs all optional dependencies.
|
||||
|
||||
Quick Start
|
||||
===========
|
||||
|
||||
Our Wiki contains an `Introduction to the API <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Introduction-to-the-API>`_ explaining how the pure Bot API can be accessed via ``python-telegram-bot``.
|
||||
|
||||
Resources
|
||||
=========
|
||||
|
||||
- The `package documentation <https://docs.python-telegram-bot.org/>`_ is the technical reference for ``python-telegram-bot``.
|
||||
It contains descriptions of all available classes, modules, methods and arguments as well as the `changelog <https://docs.python-telegram-bot.org/changelog.html>`_.
|
||||
- The `wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/>`_ is home to number of more elaborate introductions of the different features of ``python-telegram-bot`` and other useful resources that go beyond the technical documentation.
|
||||
- Our `examples section <https://docs.python-telegram-bot.org/examples.html>`_ contains several examples that showcase the different features of both the Bot API and ``python-telegram-bot``.
|
||||
Even if it is not your approach for learning, please take a look at ``echobot.py``. It is the de facto base for most of the bots out there.
|
||||
The code for these examples is released to the public domain, so you can start by grabbing the code and building on top of it.
|
||||
- The `official Telegram Bot API documentation <https://core.telegram.org/bots/api>`_ is of course always worth a read.
|
||||
|
||||
Getting help
|
||||
============
|
||||
|
||||
If the resources mentioned above don't answer your questions or simply overwhelm you, there are several ways of getting help.
|
||||
|
||||
1. We have a vibrant community of developers helping each other in our `Telegram group <https://telegram.me/pythontelegrambotgroup>`_. Join us! Asking a question here is often the quickest way to get a pointer in the right direction.
|
||||
|
||||
2. Ask questions by opening `a discussion <https://github.com/python-telegram-bot/python-telegram-bot/discussions/new>`_.
|
||||
|
||||
3. You can even ask for help on Stack Overflow using the `python-telegram-bot tag <https://stackoverflow.com/questions/tagged/python-telegram-bot>`_.
|
||||
|
||||
Concurrency
|
||||
===========
|
||||
|
||||
Since v20.0, ``python-telegram-bot`` is built on top of Pythons ``asyncio`` module.
|
||||
Because ``asyncio`` is in general single-threaded, ``python-telegram-bot`` does currently not aim to be thread-safe.
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
Contributions of all sizes are welcome.
|
||||
Please review our `contribution guidelines <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.github/CONTRIBUTING.rst>`_ to get started.
|
||||
You can also help by `reporting bugs or feature requests <https://github.com/python-telegram-bot/python-telegram-bot/issues/new/choose>`_.
|
||||
|
||||
Donating
|
||||
========
|
||||
Occasionally we are asked if we accept donations to support the development.
|
||||
While we appreciate the thought, maintaining PTB is our hobby, and we have almost no running costs for it. We therefore have nothing set up to accept donations.
|
||||
If you still want to donate, we kindly ask you to donate to another open source project/initiative of your choice instead.
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
You may copy, distribute and modify the software provided that modifications are described and licensed for free under `LGPL-3 <https://www.gnu.org/licenses/lgpl-3.0.html>`_.
|
||||
Derivatives works (including modifications or anything statically linked to the library) can only be redistributed under LGPL-3, but applications that use the library don't have to be.
|
|
@ -46,6 +46,7 @@ PRIVATE_BASE_CLASSES = {
|
|||
"_BaseThumbedMedium": "TelegramObject",
|
||||
"_BaseMedium": "TelegramObject",
|
||||
"_CredentialsBase": "TelegramObject",
|
||||
"_ChatBase": "TelegramObject",
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,9 +20,13 @@ author = "Leandro Toledo"
|
|||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = "21.2" # telegram.__version__[:3]
|
||||
|
||||
# Import needs to be below the sys.path.insert above
|
||||
import telegram # noqa: E402
|
||||
|
||||
version = telegram.__version__
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = "21.2" # telegram.__version__
|
||||
release = telegram.__version__
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
needs_sphinx = "6.1.3"
|
||||
|
|
|
@ -369,6 +369,8 @@
|
|||
- Used for getting basic info about a file
|
||||
* - :meth:`~telegram.Bot.get_me`
|
||||
- Used for getting basic information about the bot
|
||||
* - :meth:`~telegram.Bot.refund_star_payment`
|
||||
- Used for refunding a payment in Telegram Stars
|
||||
|
||||
.. raw:: html
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
Chat
|
||||
====
|
||||
|
||||
.. Also lists methods of _ChatBase, but not the ones of TelegramObject
|
||||
.. autoclass:: telegram.Chat
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TelegramObject
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
ChatFullInfo
|
||||
============
|
||||
|
||||
.. Also lists methods of _ChatBase, but not the ones of TelegramObject
|
||||
.. autoclass:: telegram.ChatFullInfo
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members: TelegramObject
|
|
@ -1,6 +1,6 @@
|
|||
PhotoSize
|
||||
=========
|
||||
.. Also lists methods of _BaseThumbedMedium, but not the ones of TelegramObject
|
||||
.. Also lists methods of _BaseMedium, but not the ones of TelegramObject
|
||||
|
||||
.. autoclass:: telegram.PhotoSize
|
||||
:members:
|
||||
|
|
|
@ -81,3 +81,9 @@
|
|||
.. |non_optional_story_argument| replace:: As of this version, this argument is now required. In accordance with our `stability policy <https://docs.python-telegram-bot.org/en/stable/stability_policy.html>`__, the signature will be kept as optional for now, though they are mandatory and an error will be raised if you don't pass it.
|
||||
|
||||
.. |business_id_str| replace:: Unique identifier of the business connection on behalf of which the message will be sent.
|
||||
|
||||
.. |message_effect_id| replace:: Unique identifier of the message effect to be added to the message; for private chats only.
|
||||
|
||||
.. |show_cap_above_med| replace:: :obj:`True`, if the caption must be shown above the message media.
|
||||
|
||||
.. |tg_stars| replace:: `Telegram Stars <https://t.me/BotNews/90>`__
|
||||
|
|
112
pyproject.toml
112
pyproject.toml
|
@ -1,7 +1,116 @@
|
|||
# PACKAGING
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
dynamic = ["version"]
|
||||
name = "python-telegram-bot"
|
||||
description = "We have made you a wrapper you can't refuse"
|
||||
readme = "README.rst"
|
||||
requires-python = ">=3.8"
|
||||
license = "LGPL-3.0-only"
|
||||
license-files = { paths = ["LICENSE", "LICENSE.dual", "LICENSE.lesser"] }
|
||||
authors = [
|
||||
{ name = "Leandro Toledo", email = "devs@python-telegram-bot.org" }
|
||||
]
|
||||
keywords = [
|
||||
"python",
|
||||
"telegram",
|
||||
"bot",
|
||||
"api",
|
||||
"wrapper",
|
||||
]
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
|
||||
"Operating System :: OS Independent",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: Communications :: Chat",
|
||||
"Topic :: Internet",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
]
|
||||
dependencies = [
|
||||
"httpx ~= 0.27",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "https://python-telegram-bot.org"
|
||||
"Documentation" = "https://docs.python-telegram-bot.org"
|
||||
"Bug Tracker" = "https://github.com/python-telegram-bot/python-telegram-bot/issues"
|
||||
"Source Code" = "https://github.com/python-telegram-bot/python-telegram-bot"
|
||||
"News" = "https://t.me/pythontelegrambotchannel"
|
||||
"Changelog" = "https://docs.python-telegram-bot.org/en/stable/changelog.html"
|
||||
"Support" = "https://t.me/pythontelegrambotgroup"
|
||||
|
||||
[project.optional-dependencies]
|
||||
# Make sure to install those as additional_dependencies in the
|
||||
# pre-commit hooks for pylint & mypy
|
||||
# Also update the readme accordingly
|
||||
#
|
||||
# When dependencies release new versions and tests succeed, we should try to expand the allowed
|
||||
# versions and only increase the lower bound if necessary
|
||||
#
|
||||
# When adding new groups, make sure to update `ext` and `all` accordingly
|
||||
|
||||
# Optional dependencies for production
|
||||
all = [
|
||||
"python-telegram-bot[ext,http2,passport,socks]",
|
||||
]
|
||||
callback-data = [
|
||||
# Cachetools doesn't have a strict stability policy. Let's be cautious for now.
|
||||
"cachetools~=5.3.3",
|
||||
]
|
||||
ext = [
|
||||
"python-telegram-bot[callback-data,job-queue,rate-limiter,webhooks]",
|
||||
]
|
||||
http2 = [
|
||||
"httpx[http2]",
|
||||
]
|
||||
job-queue = [
|
||||
# APS doesn't have a strict stability policy. Let's be cautious for now.
|
||||
"APScheduler~=3.10.4",
|
||||
# pytz is required by APS and just needs the lower bound due to #2120
|
||||
"pytz>=2018.6",
|
||||
]
|
||||
passport = [
|
||||
"cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=39.0.1",
|
||||
# cffi is a dependency of cryptography and added support for python 3.13 in 1.17.0rc1
|
||||
"cffi >= 1.17.0rc1; python_version > '3.12'"
|
||||
]
|
||||
rate-limiter = [
|
||||
"aiolimiter~=1.1.0",
|
||||
]
|
||||
socks = [
|
||||
"httpx[socks]",
|
||||
]
|
||||
webhooks = [
|
||||
# tornado is rather stable, but let's not allow the next major release without prior testing
|
||||
"tornado~=6.4",
|
||||
]
|
||||
|
||||
|
||||
# HATCH
|
||||
[tool.hatch.version]
|
||||
# dynamically evaluates the `__version__` variable in that file
|
||||
source = "code"
|
||||
path = "telegram/_version.py"
|
||||
search-paths = ["telegram"]
|
||||
|
||||
[tool.hatch.build]
|
||||
packages = ["telegram"]
|
||||
|
||||
# BLACK:
|
||||
[tool.black]
|
||||
line-length = 99
|
||||
target-version = ['py38', 'py39', 'py310', 'py311']
|
||||
|
||||
# ISORT:
|
||||
[tool.isort] # black config
|
||||
|
@ -11,7 +120,6 @@ line_length = 99
|
|||
# RUFF:
|
||||
[tool.ruff]
|
||||
line-length = 99
|
||||
target-version = "py38"
|
||||
show-fixes = true
|
||||
|
||||
[tool.ruff.lint]
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
-r requirements.txt
|
||||
-r requirements-dev.txt
|
||||
-r requirements-opts.txt
|
||||
-r docs/requirements-docs.txt
|
5
requirements-dev-all.txt
Normal file
5
requirements-dev-all.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
-e .[all]
|
||||
# needed for pre-commit hooks in the git commit command
|
||||
pre-commit
|
||||
-r requirements-unit-tests.txt
|
||||
-r docs/requirements-docs.txt
|
|
@ -1,10 +0,0 @@
|
|||
pre-commit # needed for pre-commit hooks in the git commit command
|
||||
|
||||
# For the test suite
|
||||
pytest==8.2.0
|
||||
pytest-asyncio==0.21.2 # needed because pytest doesn't come with native support for coroutines as tests
|
||||
pytest-xdist==3.6.1 # xdist runs tests in parallel
|
||||
flaky # Used for flaky tests (flaky decorator)
|
||||
beautifulsoup4 # used in test_official for parsing tg docs
|
||||
|
||||
wheel # required for building the wheels for releases
|
|
@ -1,27 +0,0 @@
|
|||
# Format:
|
||||
# package_name==version # req-1, req-2, req-3!ext
|
||||
# `pip install ptb-raw[req-1/2]` will install `package_name`
|
||||
# `pip install ptb[req-1/2/3]` will also install `package_name`
|
||||
|
||||
# Make sure to install those as additional_dependencies in the
|
||||
# pre-commit hooks for pylint & mypy
|
||||
# Also update the readme accordingly
|
||||
|
||||
# When dependencies release new versions and tests succeed, we should try to expand the allowed
|
||||
# versions and only increase the lower bound if necessary
|
||||
|
||||
httpx[socks] # socks
|
||||
httpx[http2] # http2
|
||||
cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=39.0.1 # passport
|
||||
aiolimiter~=1.1.0 # rate-limiter!ext
|
||||
|
||||
# tornado is rather stable, but let's not allow the next mayor release without prior testing
|
||||
tornado~=6.4 # webhooks!ext
|
||||
|
||||
# Cachetools and APS don't have a strict stability policy.
|
||||
# Let's be cautious for now.
|
||||
cachetools~=5.3.3 # callback-data!ext
|
||||
APScheduler~=3.10.4 # job-queue!ext
|
||||
|
||||
# pytz is required by APS and just needs the lower bound due to #2120
|
||||
pytz>=2018.6 # job-queue!ext
|
19
requirements-unit-tests.txt
Normal file
19
requirements-unit-tests.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
-e .
|
||||
|
||||
# required for building the wheels for releases
|
||||
build
|
||||
|
||||
# For the test suite
|
||||
pytest==8.2.2
|
||||
|
||||
# needed because pytest doesn't come with native support for coroutines as tests
|
||||
pytest-asyncio==0.21.2
|
||||
|
||||
# xdist runs tests in parallel
|
||||
pytest-xdist==3.6.1
|
||||
|
||||
# Used for flaky tests (flaky decorator)
|
||||
flaky
|
||||
|
||||
# used in test_official for parsing tg docs
|
||||
beautifulsoup4
|
|
@ -1,10 +0,0 @@
|
|||
# Make sure to install those as additional_dependencies in the
|
||||
# pre-commit hooks for pylint & mypy
|
||||
# Also update the readme accordingly
|
||||
|
||||
# When dependencies release new versions and tests succeed, we should try to expand the allowed
|
||||
# versions and only increase the lower bound if necessary
|
||||
|
||||
# httpx has no stable release yet, but we've had no stability problems since v20.0a0 either
|
||||
# Since there have been requests to relax the bound a bit, we allow versions < 1.0.0
|
||||
httpx ~= 0.27
|
|
@ -1,8 +1,5 @@
|
|||
[metadata]
|
||||
license_files = LICENSE, LICENSE.dual, LICENSE.lesser
|
||||
|
||||
[flake8]
|
||||
max-line-length = 99
|
||||
ignore = W503, W605
|
||||
extend-ignore = E203, E704
|
||||
exclude = setup.py, setup_raw.py docs/source/conf.py
|
||||
exclude = docs/source/conf.py
|
||||
|
|
131
setup.py
131
setup.py
|
@ -1,131 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""The setup and build script for the python-telegram-bot library."""
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
|
||||
def get_requirements() -> List[str]:
|
||||
"""Build the requirements list for this project"""
|
||||
requirements_list = []
|
||||
|
||||
with Path("requirements.txt").open(encoding="utf-8") as reqs:
|
||||
for install in reqs:
|
||||
if install.startswith("#"):
|
||||
continue
|
||||
requirements_list.append(install.strip())
|
||||
|
||||
return requirements_list
|
||||
|
||||
|
||||
def get_packages_requirements(raw: bool = False) -> Tuple[List[str], List[str]]:
|
||||
"""Build the package & requirements list for this project"""
|
||||
reqs = get_requirements()
|
||||
|
||||
exclude = ["tests*", "docs*"]
|
||||
if raw:
|
||||
exclude.append("telegram.ext*")
|
||||
|
||||
packs = find_packages(exclude=exclude)
|
||||
|
||||
return packs, reqs
|
||||
|
||||
|
||||
def get_optional_requirements(raw: bool = False) -> Dict[str, List[str]]:
|
||||
"""Build the optional dependencies"""
|
||||
requirements = defaultdict(list)
|
||||
|
||||
with Path("requirements-opts.txt").open(encoding="utf-8") as reqs:
|
||||
for line in reqs:
|
||||
effective_line = line.strip()
|
||||
if not effective_line or effective_line.startswith("#"):
|
||||
continue
|
||||
dependency, names = effective_line.split("#")
|
||||
dependency = dependency.strip()
|
||||
for name in names.split(","):
|
||||
effective_name = name.strip()
|
||||
if effective_name.endswith("!ext"):
|
||||
if raw:
|
||||
continue
|
||||
effective_name = effective_name[:-4]
|
||||
requirements["ext"].append(dependency)
|
||||
requirements[effective_name].append(dependency)
|
||||
requirements["all"].append(dependency)
|
||||
|
||||
return requirements
|
||||
|
||||
|
||||
def get_setup_kwargs(raw: bool = False) -> Dict[str, Any]:
|
||||
"""Builds a dictionary of kwargs for the setup function"""
|
||||
packages, requirements = get_packages_requirements(raw=raw)
|
||||
|
||||
raw_ext = "-raw" if raw else ""
|
||||
readme = Path(f'README{"_RAW" if raw else ""}.rst')
|
||||
|
||||
version_file = Path("telegram/_version.py").read_text(encoding="utf-8")
|
||||
first_part = version_file.split("# SETUP.PY MARKER")[0]
|
||||
exec(first_part) # pylint: disable=exec-used
|
||||
|
||||
return {
|
||||
"script_name": f"setup{raw_ext}.py",
|
||||
"name": f"python-telegram-bot{raw_ext}",
|
||||
"version": locals()["__version__"],
|
||||
"author": "Leandro Toledo",
|
||||
"author_email": "devs@python-telegram-bot.org",
|
||||
"license": "LGPLv3",
|
||||
"url": "https://python-telegram-bot.org/",
|
||||
# Keywords supported by PyPI can be found at
|
||||
# https://github.com/pypa/warehouse/blob/aafc5185e57e67d43487ce4faa95913dd4573e14/
|
||||
# warehouse/templates/packaging/detail.html#L20-L58
|
||||
"project_urls": {
|
||||
"Documentation": "https://docs.python-telegram-bot.org",
|
||||
"Bug Tracker": "https://github.com/python-telegram-bot/python-telegram-bot/issues",
|
||||
"Source Code": "https://github.com/python-telegram-bot/python-telegram-bot",
|
||||
"News": "https://t.me/pythontelegrambotchannel",
|
||||
"Changelog": "https://docs.python-telegram-bot.org/en/stable/changelog.html",
|
||||
},
|
||||
"download_url": f"https://pypi.org/project/python-telegram-bot{raw_ext}/",
|
||||
"keywords": "python telegram bot api wrapper",
|
||||
"description": "We have made you a wrapper you can't refuse",
|
||||
"long_description": readme.read_text(encoding="utf-8"),
|
||||
"long_description_content_type": "text/x-rst",
|
||||
"packages": packages,
|
||||
"install_requires": requirements,
|
||||
"extras_require": get_optional_requirements(raw=raw),
|
||||
"include_package_data": True,
|
||||
"classifiers": [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
|
||||
"Operating System :: OS Independent",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: Communications :: Chat",
|
||||
"Topic :: Internet",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
],
|
||||
"python_requires": ">=3.8",
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# If we're building, build ptb-raw as well
|
||||
if set(sys.argv[1:]) in [{"bdist_wheel"}, {"sdist"}, {"sdist", "bdist_wheel"}]:
|
||||
args = ["python", "setup_raw.py"]
|
||||
args.extend(sys.argv[1:])
|
||||
subprocess.run(args, check=True, capture_output=True)
|
||||
|
||||
setup(**get_setup_kwargs(raw=False))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""The setup and build script for the python-telegram-bot-raw library."""
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
from setup import get_setup_kwargs
|
||||
|
||||
setup(**get_setup_kwargs(raw=True))
|
|
@ -242,7 +242,6 @@ __all__ = (
|
|||
"warnings",
|
||||
)
|
||||
|
||||
|
||||
from . import _version, constants, error, helpers, request, warnings
|
||||
from ._birthdate import Birthdate
|
||||
from ._bot import Bot
|
||||
|
@ -470,8 +469,8 @@ __version_info__: _version.Version = _version.__version_info__
|
|||
#:
|
||||
#: .. versionchanged:: 20.0
|
||||
#: This constant was previously named ``bot_api_version``.
|
||||
__bot_api_version__: str = _version.__bot_api_version__
|
||||
__bot_api_version__: str = constants.BOT_API_VERSION
|
||||
#: :class:`typing.NamedTuple`: Shortcut for :const:`telegram.constants.BOT_API_VERSION_INFO`.
|
||||
#:
|
||||
#: .. versionadded:: 20.0
|
||||
__bot_api_version_info__: constants._BotAPIVersion = _version.__bot_api_version_info__
|
||||
__bot_api_version_info__: constants._BotAPIVersion = constants.BOT_API_VERSION_INFO
|
||||
|
|
239
telegram/_bot.py
239
telegram/_bot.py
|
@ -672,6 +672,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
link_preview_options: ODVInput["LinkPreviewOptions"] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -711,6 +712,8 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
data["disable_notification"] = disable_notification
|
||||
data["protect_content"] = protect_content
|
||||
data["parse_mode"] = parse_mode
|
||||
|
||||
if reply_parameters is not None:
|
||||
data["reply_parameters"] = reply_parameters
|
||||
|
||||
if link_preview_options is not None:
|
||||
|
@ -731,6 +734,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
if business_connection_id is not None:
|
||||
data["business_connection_id"] = business_connection_id
|
||||
|
||||
if message_effect_id is not None:
|
||||
data["message_effect_id"] = message_effect_id
|
||||
|
||||
result = await self._post(
|
||||
endpoint,
|
||||
data,
|
||||
|
@ -919,6 +925,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -967,6 +974,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -1024,6 +1034,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
parse_mode=parse_mode,
|
||||
link_preview_options=link_preview_options,
|
||||
reply_parameters=reply_parameters,
|
||||
message_effect_id=message_effect_id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
|
@ -1152,7 +1163,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
Note:
|
||||
Since the release of Bot API 5.5 it can be impossible to forward messages from
|
||||
some chats. Use the attributes :attr:`telegram.Message.has_protected_content` and
|
||||
:attr:`telegram.Chat.has_protected_content` to check this.
|
||||
:attr:`telegram.ChatFullInfo.has_protected_content` to check this.
|
||||
|
||||
As a workaround, it is still possible to use :meth:`copy_message`. However, this
|
||||
behaviour is undocumented and might be changed by Telegram.
|
||||
|
@ -1272,6 +1283,8 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -1335,6 +1348,12 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -1372,6 +1391,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"chat_id": chat_id,
|
||||
"photo": self._parse_file_input(photo, PhotoSize, filename=filename),
|
||||
"has_spoiler": has_spoiler,
|
||||
"show_caption_above_media": show_caption_above_media,
|
||||
}
|
||||
|
||||
return await self._send_message(
|
||||
|
@ -1393,6 +1413,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_audio(
|
||||
|
@ -1412,6 +1433,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -1484,6 +1506,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -1545,6 +1570,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_document(
|
||||
|
@ -1562,6 +1588,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -1633,6 +1660,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -1690,6 +1720,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_sticker(
|
||||
|
@ -1703,6 +1734,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
emoji: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -1754,6 +1786,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -1803,6 +1838,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_video(
|
||||
|
@ -1824,6 +1860,8 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -1904,6 +1942,12 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -1946,6 +1990,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"supports_streaming": supports_streaming,
|
||||
"thumbnail": self._parse_file_input(thumbnail, attach=True) if thumbnail else None,
|
||||
"has_spoiler": has_spoiler,
|
||||
"show_caption_above_media": show_caption_above_media,
|
||||
}
|
||||
|
||||
return await self._send_message(
|
||||
|
@ -1967,6 +2012,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_video_note(
|
||||
|
@ -1982,6 +2028,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2047,6 +2094,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -2104,6 +2154,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_animation(
|
||||
|
@ -2124,6 +2175,8 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2198,6 +2251,12 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -2239,6 +2298,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"height": height,
|
||||
"thumbnail": self._parse_file_input(thumbnail, attach=True) if thumbnail else None,
|
||||
"has_spoiler": has_spoiler,
|
||||
"show_caption_above_media": show_caption_above_media,
|
||||
}
|
||||
|
||||
return await self._send_message(
|
||||
|
@ -2260,6 +2320,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_voice(
|
||||
|
@ -2276,6 +2337,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2344,6 +2406,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -2402,6 +2467,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_media_group(
|
||||
|
@ -2415,6 +2481,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2465,6 +2532,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -2558,6 +2628,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"message_thread_id": message_thread_id,
|
||||
"reply_parameters": reply_parameters,
|
||||
"business_connection_id": business_connection_id,
|
||||
"message_effect_id": message_effect_id,
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
|
@ -2587,6 +2658,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2643,6 +2715,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -2712,6 +2787,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def edit_message_live_location(
|
||||
|
@ -2883,6 +2959,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2935,6 +3012,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -3015,6 +3095,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_contact(
|
||||
|
@ -3030,6 +3111,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -3072,6 +3154,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -3143,6 +3228,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_game(
|
||||
|
@ -3155,6 +3241,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -3187,6 +3274,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -3233,6 +3323,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_chat_action(
|
||||
|
@ -3954,6 +4045,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
@ -3985,6 +4077,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
|sequenceargs|
|
||||
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an
|
||||
inline keyboard.
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, if edited message is not an inline message, the
|
||||
|
@ -3998,6 +4093,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"chat_id": chat_id,
|
||||
"message_id": message_id,
|
||||
"inline_message_id": inline_message_id,
|
||||
"show_caption_above_media": show_caption_above_media,
|
||||
}
|
||||
|
||||
return await self._send_message(
|
||||
|
@ -4610,8 +4706,8 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
) -> bool:
|
||||
"""Use this method to set a new group sticker set for a supergroup.
|
||||
The bot must be an administrator in the chat for this to work and must have the appropriate
|
||||
admin rights. Use the field :attr:`telegram.Chat.can_set_sticker_set` optionally returned
|
||||
in :meth:`get_chat` requests to check if the bot can use this method.
|
||||
admin rights. Use the field :attr:`telegram.ChatFullInfo.can_set_sticker_set` optionally
|
||||
returned in :meth:`get_chat` requests to check if the bot can use this method.
|
||||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
|
||||
|
@ -4644,7 +4740,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
) -> bool:
|
||||
"""Use this method to delete a group sticker set from a supergroup. The bot must be an
|
||||
administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
Use the field :attr:`telegram.Chat.can_set_sticker_set` optionally returned in
|
||||
Use the field :attr:`telegram.ChatFullInfo.can_set_sticker_set` optionally returned in
|
||||
:meth:`get_chat` requests to check if the bot can use this method.
|
||||
|
||||
Args:
|
||||
|
@ -4822,7 +4918,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
title: str,
|
||||
description: str,
|
||||
payload: str,
|
||||
provider_token: str,
|
||||
provider_token: Optional[str], # This arg is now optional as of Bot API 7.4
|
||||
currency: str,
|
||||
prices: Sequence["LabeledPrice"],
|
||||
start_parameter: Optional[str] = None,
|
||||
|
@ -4845,6 +4941,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -4876,12 +4973,19 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
:tg-const:`telegram.Invoice.MAX_PAYLOAD_LENGTH` bytes. This will not be
|
||||
displayed to the user, use for your internal processes.
|
||||
provider_token (:obj:`str`): Payments provider token, obtained via
|
||||
`@BotFather <https://t.me/BotFather>`_.
|
||||
`@BotFather <https://t.me/BotFather>`_. Pass an empty string for payments in
|
||||
|tg_stars|.
|
||||
|
||||
.. deprecated:: 21.3
|
||||
As of Bot API 7.4, this parameter is now optional and future versions of the
|
||||
library will make it optional as well.
|
||||
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, see `more on currencies
|
||||
<https://core.telegram.org/bots/payments#supported-currencies>`_.
|
||||
<https://core.telegram.org/bots/payments#supported-currencies>`_. Pass ``XTR`` for
|
||||
payment in |tg_stars|.
|
||||
prices (Sequence[:class:`telegram.LabeledPrice`]): Price breakdown, a sequence
|
||||
of components (e.g. product price, tax, discount, delivery cost, delivery tax,
|
||||
bonus, etc.).
|
||||
bonus, etc.). Must contain exactly one item for payment in |tg_stars|.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|sequenceargs|
|
||||
|
@ -4890,7 +4994,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
a maximum tip of US$ 1.45 pass ``max_tip_amount = 145``. See the exp parameter in
|
||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, it
|
||||
shows the number of digits past the decimal point for each currency (2 for the
|
||||
majority of currencies). Defaults to ``0``.
|
||||
majority of currencies). Defaults to ``0``. Not supported for payment in |tg_stars|
|
||||
|
||||
.. versionadded:: 13.5
|
||||
suggested_tip_amounts (Sequence[:obj:`int`], optional): An array of
|
||||
|
@ -4923,19 +5027,20 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
photo_width (:obj:`int`, optional): Photo width.
|
||||
photo_height (:obj:`int`, optional): Photo height.
|
||||
need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full
|
||||
name to complete the order.
|
||||
name to complete the order. Ignored for payments in |tg_stars|.
|
||||
need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's
|
||||
phone number to complete the order.
|
||||
phone number to complete the order. Ignored for payments in |tg_stars|.
|
||||
need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email
|
||||
to complete the order.
|
||||
to complete the order. Ignored for payments in |tg_stars|.
|
||||
need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the
|
||||
user's shipping address to complete the order.
|
||||
user's shipping address to complete the order. Ignored for payments in
|
||||
|tg_stars|.
|
||||
send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's
|
||||
phone number should be sent to provider.
|
||||
phone number should be sent to provider. Ignored for payments in |tg_stars|.
|
||||
send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email
|
||||
address should be sent to provider.
|
||||
address should be sent to provider. Ignored for payments in |tg_stars|.
|
||||
is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on
|
||||
the shipping method.
|
||||
the shipping method. Ignored for payments in |tg_stars|.
|
||||
disable_notification (:obj:`bool`, optional): |disable_notification|
|
||||
protect_content (:obj:`bool`, optional): |protect_content|
|
||||
|
||||
|
@ -4950,6 +5055,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -5018,6 +5126,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def answer_shipping_query(
|
||||
|
@ -6839,6 +6948,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
business_connection_id: Optional[str] = None,
|
||||
question_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
question_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -6933,6 +7043,9 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
:paramref:`question_parse_mode`.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -6998,6 +7111,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def stop_poll(
|
||||
|
@ -7055,6 +7169,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -7101,6 +7216,9 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: 21.1
|
||||
message_effect_id (:obj:`str`, optional): |message_effect_id|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -7148,6 +7266,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def get_my_default_administrator_rights(
|
||||
|
@ -7417,7 +7536,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
minutes.
|
||||
|
||||
Returns:
|
||||
:obj:`True`: On success
|
||||
:obj:`True`: On success, :obj:`True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
@ -7448,7 +7567,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
10 minutes after the bot is launched.
|
||||
|
||||
Returns:
|
||||
:obj:`True`: On success
|
||||
:obj:`True`: On success, :obj:`True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
@ -7476,6 +7595,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -7519,6 +7639,9 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -7541,7 +7664,8 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
|keyword_only_arg|
|
||||
|
||||
Returns:
|
||||
:class:`telegram.MessageId`: On success
|
||||
:class:`telegram.MessageId`: On success, the :class:`telegram.MessageId` of the sent
|
||||
message is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
@ -7575,6 +7699,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"reply_markup": reply_markup,
|
||||
"message_thread_id": message_thread_id,
|
||||
"reply_parameters": reply_parameters,
|
||||
"show_caption_above_media": show_caption_above_media,
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
|
@ -7743,7 +7868,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
title: str,
|
||||
description: str,
|
||||
payload: str,
|
||||
provider_token: str,
|
||||
provider_token: Optional[str], # This arg is now optional as of Bot API 7.4
|
||||
currency: str,
|
||||
prices: Sequence["LabeledPrice"],
|
||||
max_tip_amount: Optional[int] = None,
|
||||
|
@ -7782,12 +7907,19 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
:tg-const:`telegram.Invoice.MAX_PAYLOAD_LENGTH` bytes. This will not be
|
||||
displayed to the user, use for your internal processes.
|
||||
provider_token (:obj:`str`): Payments provider token, obtained via
|
||||
`@BotFather <https://t.me/BotFather>`_.
|
||||
`@BotFather <https://t.me/BotFather>`_. Pass an empty string for payments in
|
||||
|tg_stars|.
|
||||
|
||||
.. deprecated:: 21.3
|
||||
As of Bot API 7.4, this parameter is now optional and future versions of the
|
||||
library will make it optional as well.
|
||||
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, see `more on currencies
|
||||
<https://core.telegram.org/bots/payments#supported-currencies>`_.
|
||||
<https://core.telegram.org/bots/payments#supported-currencies>`_. Pass ``XTR`` for
|
||||
payments in |tg_stars|.
|
||||
prices (Sequence[:class:`telegram.LabeledPrice`)]: Price breakdown, a sequence
|
||||
of components (e.g. product price, tax, discount, delivery cost, delivery tax,
|
||||
bonus, etc.).
|
||||
bonus, etc.). Must contain exactly one item for payments in |tg_stars|.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|sequenceargs|
|
||||
|
@ -7796,7 +7928,8 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
a maximum tip of US$ 1.45 pass ``max_tip_amount = 145``. See the exp parameter in
|
||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, it
|
||||
shows the number of digits past the decimal point for each currency (2 for the
|
||||
majority of currencies). Defaults to ``0``.
|
||||
majority of currencies). Defaults to ``0``. Not supported for payments in
|
||||
|tg_stars|.
|
||||
suggested_tip_amounts (Sequence[:obj:`int`], optional): An array of
|
||||
suggested amounts of tips in the *smallest* units of the currency (integer, **not**
|
||||
float/double). At most :tg-const:`telegram.Invoice.MAX_TIP_AMOUNTS` suggested tip
|
||||
|
@ -7815,19 +7948,20 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
photo_width (:obj:`int`, optional): Photo width.
|
||||
photo_height (:obj:`int`, optional): Photo height.
|
||||
need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full
|
||||
name to complete the order.
|
||||
name to complete the order. Ignored for payments in |tg_stars|.
|
||||
need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's
|
||||
phone number to complete the order.
|
||||
phone number to complete the order. Ignored for payments in |tg_stars|.
|
||||
need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email
|
||||
address to complete the order.
|
||||
address to complete the order. Ignored for payments in |tg_stars|.
|
||||
need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the
|
||||
user's shipping address to complete the order.
|
||||
user's shipping address to complete the order. Ignored for payments in
|
||||
|tg_stars|.
|
||||
send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's
|
||||
phone number should be sent to provider.
|
||||
phone number should be sent to provider. Ignored for payments in |tg_stars|.
|
||||
send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email
|
||||
address should be sent to provider.
|
||||
address should be sent to provider. Ignored for payments in |tg_stars|.
|
||||
is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on
|
||||
the shipping method.
|
||||
the shipping method. Ignored for payments in |tg_stars|.
|
||||
|
||||
Returns:
|
||||
:class:`str`: On success, the created invoice link is returned.
|
||||
|
@ -8895,6 +9029,47 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def refund_star_payment(
|
||||
self,
|
||||
user_id: int,
|
||||
telegram_payment_charge_id: str,
|
||||
*,
|
||||
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:
|
||||
"""Refunds a successful payment in |tg_stars|.
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Args:
|
||||
user_id (:obj:`int`): User identifier of the user whose payment will be refunded.
|
||||
telegram_payment_charge_id (:obj:`str`): Telegram payment identifier.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
data: JSONDict = {
|
||||
"user_id": user_id,
|
||||
"telegram_payment_charge_id": telegram_payment_charge_id,
|
||||
}
|
||||
|
||||
return await self._post(
|
||||
"refundStarPayment",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def to_dict(self, recursive: bool = True) -> JSONDict: # noqa: ARG002
|
||||
"""See :meth:`telegram.TelegramObject.to_dict`."""
|
||||
data: JSONDict = {"id": self.id, "username": self.username, "first_name": self.first_name}
|
||||
|
@ -9145,3 +9320,5 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"""Alias for :meth:`get_business_connection`"""
|
||||
replaceStickerInSet = replace_sticker_in_set
|
||||
"""Alias for :meth:`replace_sticker_in_set`"""
|
||||
refundStarPayment = refund_star_payment
|
||||
"""Alias for :meth:`refund_star_payment`"""
|
||||
|
|
|
@ -281,6 +281,7 @@ class CallbackQuery(TelegramObject):
|
|||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
@ -326,6 +327,7 @@ class CallbackQuery(TelegramObject):
|
|||
caption_entities=caption_entities,
|
||||
chat_id=None,
|
||||
message_id=None,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
return await self._get_message().edit_caption(
|
||||
caption=caption,
|
||||
|
@ -337,6 +339,7 @@ class CallbackQuery(TelegramObject):
|
|||
parse_mode=parse_mode,
|
||||
api_kwargs=api_kwargs,
|
||||
caption_entities=caption_entities,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def edit_message_reply_markup(
|
||||
|
@ -815,6 +818,7 @@ class CallbackQuery(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -861,6 +865,7 @@ class CallbackQuery(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
reply_parameters=reply_parameters,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
MAX_ANSWER_TEXT_LENGTH: Final[int] = (
|
||||
|
|
1075
telegram/_chat.py
1075
telegram/_chat.py
File diff suppressed because it is too large
Load diff
|
@ -19,58 +19,380 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram ChatFullInfo."""
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Optional, Sequence
|
||||
from typing import TYPE_CHECKING, Optional, Sequence, Tuple
|
||||
|
||||
from telegram._birthdate import Birthdate
|
||||
from telegram._chat import Chat
|
||||
from telegram._chat import Chat, _ChatBase
|
||||
from telegram._chatlocation import ChatLocation
|
||||
from telegram._chatpermissions import ChatPermissions
|
||||
from telegram._files.chatphoto import ChatPhoto
|
||||
from telegram._reaction import ReactionType
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import BusinessIntro, BusinessLocation, BusinessOpeningHours, Message
|
||||
from telegram import Bot, BusinessIntro, BusinessLocation, BusinessOpeningHours, Message
|
||||
|
||||
|
||||
class ChatFullInfo(Chat):
|
||||
class ChatFullInfo(_ChatBase):
|
||||
"""
|
||||
This object contains full information about a chat.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`~telegram.Chat.id` is equal.
|
||||
|
||||
Caution:
|
||||
This class is a subclass of :class:`telegram.Chat` and inherits all attributes and methods
|
||||
for backwards compatibility. In the future, this class will *NOT* inherit from
|
||||
.. versionadded:: 21.2
|
||||
|
||||
.. versionchanged:: 21.3
|
||||
Explicit support for all shortcut methods known from :class:`telegram.Chat` on this
|
||||
object. Previously those were only available because this class inherited from
|
||||
:class:`telegram.Chat`.
|
||||
|
||||
.. seealso::
|
||||
All arguments and attributes can be found in :class:`telegram.Chat`.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
|
||||
Args:
|
||||
id (:obj:`int`): Unique identifier for this chat.
|
||||
type (:obj:`str`): Type of chat, can be either :attr:`PRIVATE`, :attr:`GROUP`,
|
||||
:attr:`SUPERGROUP` or :attr:`CHANNEL`.
|
||||
accent_color_id (:obj:`int`, optional): Identifier of the
|
||||
:class:`accent color <telegram.constants.AccentColor>` for the chat name and
|
||||
backgrounds of the chat photo, reply header, and link preview. See `accent colors`_
|
||||
for more details.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
max_reaction_count (:obj:`int`): The maximum number of reactions that can be set on a
|
||||
message in the chat.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
title (:obj:`str`, optional): Title, for supergroups, channels and group chats.
|
||||
username (:obj:`str`, optional): Username, for private chats, supergroups and channels if
|
||||
available.
|
||||
first_name (:obj:`str`, optional): First name of the other party in a private chat.
|
||||
last_name (:obj:`str`, optional): Last name of the other party in a private chat.
|
||||
is_forum (:obj:`bool`, optional): :obj:`True`, if the supergroup chat is a forum
|
||||
(has topics_ enabled).
|
||||
|
||||
.. versionadded:: 20.0
|
||||
photo (:class:`telegram.ChatPhoto`, optional): Chat photo.
|
||||
active_usernames (Sequence[:obj:`str`], optional): If set, the list of all `active chat
|
||||
usernames <https://telegram.org/blog/topics-in-groups-collectible-usernames\
|
||||
#collectible-usernames>`_; for private chats, supergroups and channels.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
birthdate (:obj:`telegram.Birthdate`, optional): For private chats,
|
||||
the date of birth of the user.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
business_intro (:class:`telegram.BusinessIntro`, optional): For private chats with
|
||||
business accounts, the intro of the business.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
business_location (:class:`telegram.BusinessLocation`, optional): For private chats with
|
||||
business accounts, the location of the business.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
business_opening_hours (:class:`telegram.BusinessOpeningHours`, optional): For private
|
||||
chats with business accounts, the opening hours of the business.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
personal_chat (:obj:`telegram.Chat`, optional): For private chats, the personal channel of
|
||||
the user.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
available_reactions (Sequence[:class:`telegram.ReactionType`], optional): List of available
|
||||
reactions allowed in the chat. If omitted, then all of
|
||||
:const:`telegram.constants.ReactionEmoji` are allowed.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
background_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of emoji chosen
|
||||
by the chat for the reply header and link preview background.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
profile_accent_color_id (:obj:`int`, optional): Identifier of the
|
||||
:class:`accent color <telegram.constants.ProfileAccentColor>` for the chat's profile
|
||||
background. See profile `accent colors`_ for more details.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
profile_background_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of
|
||||
the emoji chosen by the chat for its profile background.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
emoji_status_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of emoji
|
||||
status of the chat or the other party in a private chat.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
emoji_status_expiration_date (:class:`datetime.datetime`, optional): Expiration date of
|
||||
emoji status of the chat or the other party in a private chat, in seconds.
|
||||
|
||||
|datetime_localization|
|
||||
|
||||
.. versionadded:: 20.5
|
||||
bio (:obj:`str`, optional): Bio of the other party in a private chat.
|
||||
has_private_forwards (:obj:`bool`, optional): :obj:`True`, if privacy settings of the other
|
||||
party in the private chat allows to use ``tg://user?id=<user_id>`` links only in chats
|
||||
with the user.
|
||||
|
||||
.. versionadded:: 13.9
|
||||
has_restricted_voice_and_video_messages (:obj:`bool`, optional): :obj:`True`, if the
|
||||
privacy settings of the other party restrict sending voice and video note messages
|
||||
in the private chat.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
join_to_send_messages (:obj:`bool`, optional): :obj:`True`, if users need to join the
|
||||
supergroup before they can send messages.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
join_by_request (:obj:`bool`, optional): :obj:`True`, if all users directly joining the
|
||||
supergroup without using an invite link need to be approved by supergroup
|
||||
administrators.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
description (:obj:`str`, optional): Description, for groups, supergroups and channel chats.
|
||||
invite_link (:obj:`str`, optional): Primary invite link, for groups, supergroups and
|
||||
channel.
|
||||
pinned_message (:class:`telegram.Message`, optional): The most recent pinned message
|
||||
(by sending date).
|
||||
permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions,
|
||||
for groups and supergroups.
|
||||
slow_mode_delay (:obj:`int`, optional): For supergroups, the minimum allowed delay between
|
||||
consecutive messages sent by each unprivileged user.
|
||||
unrestrict_boost_count (:obj:`int`, optional): For supergroups, the minimum number of
|
||||
boosts that a non-administrator user needs to add in order to ignore slow mode and chat
|
||||
permissions.
|
||||
|
||||
.. versionadded:: 21.0
|
||||
message_auto_delete_time (:obj:`int`, optional): The time after which all messages sent to
|
||||
the chat will be automatically deleted; in seconds.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
has_aggressive_anti_spam_enabled (:obj:`bool`, optional): :obj:`True`, if aggressive
|
||||
anti-spam checks are enabled in the supergroup. The field is only available to chat
|
||||
administrators.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
has_hidden_members (:obj:`bool`, optional): :obj:`True`, if non-administrators can only
|
||||
get the list of bots and administrators in the chat.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
has_protected_content (:obj:`bool`, optional): :obj:`True`, if messages from the chat can't
|
||||
be forwarded to other chats.
|
||||
|
||||
.. versionadded:: 13.9
|
||||
has_visible_history (:obj:`bool`, optional): :obj:`True`, if new chat members will have
|
||||
access to old messages; available only to chat administrators.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
sticker_set_name (:obj:`str`, optional): For supergroups, name of group sticker set.
|
||||
can_set_sticker_set (:obj:`bool`, optional): :obj:`True`, if the bot can change group the
|
||||
sticker set.
|
||||
custom_emoji_sticker_set_name (:obj:`str`, optional): For supergroups, the name of the
|
||||
group's custom emoji sticker set. Custom emoji from this set can be used by all users
|
||||
and bots in the group.
|
||||
|
||||
.. versionadded:: 21.0
|
||||
linked_chat_id (:obj:`int`, optional): Unique identifier for the linked chat, i.e. the
|
||||
discussion group identifier for a channel and vice versa; for supergroups and channel
|
||||
chats.
|
||||
location (:class:`telegram.ChatLocation`, optional): For supergroups, the location to which
|
||||
the supergroup is connected.
|
||||
|
||||
Attributes:
|
||||
id (:obj:`int`): Unique identifier for this chat.
|
||||
type (:obj:`str`): Type of chat, can be either :attr:`PRIVATE`, :attr:`GROUP`,
|
||||
:attr:`SUPERGROUP` or :attr:`CHANNEL`.
|
||||
accent_color_id (:obj:`int`): Optional. Identifier of the
|
||||
:class:`accent color <telegram.constants.AccentColor>` for the chat name and
|
||||
backgrounds of the chat photo, reply header, and link preview. See `accent colors`_
|
||||
for more details.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
max_reaction_count (:obj:`int`): The maximum number of reactions that can be set on a
|
||||
message in the chat.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
title (:obj:`str`, optional): Title, for supergroups, channels and group chats.
|
||||
username (:obj:`str`, optional): Username, for private chats, supergroups and channels if
|
||||
available.
|
||||
first_name (:obj:`str`, optional): First name of the other party in a private chat.
|
||||
last_name (:obj:`str`, optional): Last name of the other party in a private chat.
|
||||
is_forum (:obj:`bool`, optional): :obj:`True`, if the supergroup chat is a forum
|
||||
(has topics_ enabled).
|
||||
|
||||
.. versionadded:: 20.0
|
||||
photo (:class:`telegram.ChatPhoto`): Optional. Chat photo.
|
||||
active_usernames (Tuple[:obj:`str`]): Optional. If set, the list of all `active chat
|
||||
usernames <https://telegram.org/blog/topics-in-groups-collectible-usernames\
|
||||
#collectible-usernames>`_; for private chats, supergroups and channels.
|
||||
|
||||
This list is empty if the chat has no active usernames or this chat instance was not
|
||||
obtained via :meth:`~telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
birthdate (:obj:`telegram.Birthdate`): Optional. For private chats,
|
||||
the date of birth of the user.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
business_intro (:class:`telegram.BusinessIntro`): Optional. For private chats with
|
||||
business accounts, the intro of the business.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
business_location (:class:`telegram.BusinessLocation`): Optional. For private chats with
|
||||
business accounts, the location of the business.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
business_opening_hours (:class:`telegram.BusinessOpeningHours`): Optional. For private
|
||||
chats with business accounts, the opening hours of the business.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
personal_chat (:obj:`telegram.Chat`): Optional. For private chats, the personal channel of
|
||||
the user.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
available_reactions (Tuple[:class:`telegram.ReactionType`]): Optional. List of available
|
||||
reactions allowed in the chat. If omitted, then all of
|
||||
:const:`telegram.constants.ReactionEmoji` are allowed.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
background_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of emoji chosen
|
||||
by the chat for the reply header and link preview background.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
profile_accent_color_id (:obj:`int`): Optional. Identifier of the
|
||||
:class:`accent color <telegram.constants.ProfileAccentColor>` for the chat's profile
|
||||
background. See profile `accent colors`_ for more details.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
profile_background_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of
|
||||
the emoji chosen by the chat for its profile background.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
emoji_status_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of emoji
|
||||
status of the chat or the other party in a private chat.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
emoji_status_expiration_date (:class:`datetime.datetime`): Optional. Expiration date of
|
||||
emoji status of the chat or the other party in a private chat, in seconds.
|
||||
|
||||
|datetime_localization|
|
||||
|
||||
.. versionadded:: 20.5
|
||||
bio (:obj:`str`): Optional. Bio of the other party in a private chat.
|
||||
has_private_forwards (:obj:`bool`): Optional. :obj:`True`, if privacy settings of the other
|
||||
party in the private chat allows to use ``tg://user?id=<user_id>`` links only in chats
|
||||
with the user.
|
||||
|
||||
.. versionadded:: 13.9
|
||||
has_restricted_voice_and_video_messages (:obj:`bool`): Optional. :obj:`True`, if the
|
||||
privacy settings of the other party restrict sending voice and video note messages
|
||||
in the private chat.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
join_to_send_messages (:obj:`bool`): Optional. :obj:`True`, if users need to join
|
||||
the supergroup before they can send messages.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
join_by_request (:obj:`bool`): Optional. :obj:`True`, if all users directly joining the
|
||||
supergroup without using an invite link need to be approved by supergroup
|
||||
administrators.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
description (:obj:`str`): Optional. Description, for groups, supergroups and channel chats.
|
||||
invite_link (:obj:`str`): Optional. Primary invite link, for groups, supergroups and
|
||||
channel.
|
||||
pinned_message (:class:`telegram.Message`): Optional. The most recent pinned message
|
||||
(by sending date).
|
||||
permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions,
|
||||
for groups and supergroups.
|
||||
slow_mode_delay (:obj:`int`): Optional. For supergroups, the minimum allowed delay between
|
||||
consecutive messages sent by each unprivileged user.
|
||||
unrestrict_boost_count (:obj:`int`): Optional. For supergroups, the minimum number of
|
||||
boosts that a non-administrator user needs to add in order to ignore slow mode and chat
|
||||
permissions.
|
||||
|
||||
.. versionadded:: 21.0
|
||||
message_auto_delete_time (:obj:`int`): Optional. The time after which all messages sent to
|
||||
the chat will be automatically deleted; in seconds.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
has_aggressive_anti_spam_enabled (:obj:`bool`): Optional. :obj:`True`, if aggressive
|
||||
anti-spam checks are enabled in the supergroup. The field is only available to chat
|
||||
administrators.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
has_hidden_members (:obj:`bool`): Optional. :obj:`True`, if non-administrators can only
|
||||
get the list of bots and administrators in the chat.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
has_protected_content (:obj:`bool`): Optional. :obj:`True`, if messages from the chat can't
|
||||
be forwarded to other chats.
|
||||
|
||||
.. versionadded:: 13.9
|
||||
has_visible_history (:obj:`bool`): Optional. :obj:`True`, if new chat members will have
|
||||
access to old messages; available only to chat administrators.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
sticker_set_name (:obj:`str`): Optional. For supergroups, name of Group sticker set.
|
||||
can_set_sticker_set (:obj:`bool`): Optional. :obj:`True`, if the bot can change group the
|
||||
sticker set.
|
||||
custom_emoji_sticker_set_name (:obj:`str`): Optional. For supergroups, the name of the
|
||||
group's custom emoji sticker set. Custom emoji from this set can be used by all users
|
||||
and bots in the group.
|
||||
|
||||
.. versionadded:: 21.0
|
||||
linked_chat_id (:obj:`int`): Optional. Unique identifier for the linked chat, i.e. the
|
||||
discussion group identifier for a channel and vice versa; for supergroups and channel
|
||||
chats.
|
||||
location (:class:`telegram.ChatLocation`): Optional. For supergroups, the location to which
|
||||
the supergroup is connected.
|
||||
|
||||
.. _accent colors: https://core.telegram.org/bots/api#accent-colors
|
||||
.. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups
|
||||
"""
|
||||
|
||||
__slots__ = ("max_reaction_count",)
|
||||
__slots__ = (
|
||||
"accent_color_id",
|
||||
"active_usernames",
|
||||
"available_reactions",
|
||||
"background_custom_emoji_id",
|
||||
"bio",
|
||||
"birthdate",
|
||||
"business_intro",
|
||||
"business_location",
|
||||
"business_opening_hours",
|
||||
"can_set_sticker_set",
|
||||
"custom_emoji_sticker_set_name",
|
||||
"description",
|
||||
"emoji_status_custom_emoji_id",
|
||||
"emoji_status_expiration_date",
|
||||
"has_aggressive_anti_spam_enabled",
|
||||
"has_hidden_members",
|
||||
"has_private_forwards",
|
||||
"has_protected_content",
|
||||
"has_restricted_voice_and_video_messages",
|
||||
"has_visible_history",
|
||||
"invite_link",
|
||||
"join_by_request",
|
||||
"join_to_send_messages",
|
||||
"linked_chat_id",
|
||||
"location",
|
||||
"max_reaction_count",
|
||||
"message_auto_delete_time",
|
||||
"permissions",
|
||||
"personal_chat",
|
||||
"photo",
|
||||
"pinned_message",
|
||||
"profile_accent_color_id",
|
||||
"profile_background_custom_emoji_id",
|
||||
"slow_mode_delay",
|
||||
"sticker_set_name",
|
||||
"unrestrict_boost_count",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id: int,
|
||||
type: str,
|
||||
accent_color_id: int, # API 7.3 made this argument required
|
||||
max_reaction_count: int, # NEW arg in api 7.3 and is required
|
||||
accent_color_id: int,
|
||||
max_reaction_count: int,
|
||||
title: Optional[str] = None,
|
||||
username: Optional[str] = None,
|
||||
first_name: Optional[str] = None,
|
||||
|
@ -120,47 +442,93 @@ class ChatFullInfo(Chat):
|
|||
username=username,
|
||||
first_name=first_name,
|
||||
last_name=last_name,
|
||||
photo=photo,
|
||||
description=description,
|
||||
invite_link=invite_link,
|
||||
pinned_message=pinned_message,
|
||||
permissions=permissions,
|
||||
sticker_set_name=sticker_set_name,
|
||||
can_set_sticker_set=can_set_sticker_set,
|
||||
slow_mode_delay=slow_mode_delay,
|
||||
bio=bio,
|
||||
linked_chat_id=linked_chat_id,
|
||||
location=location,
|
||||
message_auto_delete_time=message_auto_delete_time,
|
||||
has_private_forwards=has_private_forwards,
|
||||
has_protected_content=has_protected_content,
|
||||
join_to_send_messages=join_to_send_messages,
|
||||
join_by_request=join_by_request,
|
||||
has_restricted_voice_and_video_messages=has_restricted_voice_and_video_messages,
|
||||
is_forum=is_forum,
|
||||
active_usernames=active_usernames,
|
||||
emoji_status_custom_emoji_id=emoji_status_custom_emoji_id,
|
||||
emoji_status_expiration_date=emoji_status_expiration_date,
|
||||
has_aggressive_anti_spam_enabled=has_aggressive_anti_spam_enabled,
|
||||
has_hidden_members=has_hidden_members,
|
||||
available_reactions=available_reactions,
|
||||
accent_color_id=accent_color_id,
|
||||
background_custom_emoji_id=background_custom_emoji_id,
|
||||
profile_accent_color_id=profile_accent_color_id,
|
||||
profile_background_custom_emoji_id=profile_background_custom_emoji_id,
|
||||
has_visible_history=has_visible_history,
|
||||
unrestrict_boost_count=unrestrict_boost_count,
|
||||
custom_emoji_sticker_set_name=custom_emoji_sticker_set_name,
|
||||
birthdate=birthdate,
|
||||
personal_chat=personal_chat,
|
||||
business_intro=business_intro,
|
||||
business_location=business_location,
|
||||
business_opening_hours=business_opening_hours,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
# Required and unique to this class-
|
||||
with self._unfrozen():
|
||||
self.max_reaction_count: int = max_reaction_count
|
||||
self.photo: Optional[ChatPhoto] = photo
|
||||
self.bio: Optional[str] = bio
|
||||
self.has_private_forwards: Optional[bool] = has_private_forwards
|
||||
self.description: Optional[str] = description
|
||||
self.invite_link: Optional[str] = invite_link
|
||||
self.pinned_message: Optional[Message] = pinned_message
|
||||
self.permissions: Optional[ChatPermissions] = permissions
|
||||
self.slow_mode_delay: Optional[int] = slow_mode_delay
|
||||
self.message_auto_delete_time: Optional[int] = (
|
||||
int(message_auto_delete_time) if message_auto_delete_time is not None else None
|
||||
)
|
||||
self.has_protected_content: Optional[bool] = has_protected_content
|
||||
self.has_visible_history: Optional[bool] = has_visible_history
|
||||
self.sticker_set_name: Optional[str] = sticker_set_name
|
||||
self.can_set_sticker_set: Optional[bool] = can_set_sticker_set
|
||||
self.linked_chat_id: Optional[int] = linked_chat_id
|
||||
self.location: Optional[ChatLocation] = location
|
||||
self.join_to_send_messages: Optional[bool] = join_to_send_messages
|
||||
self.join_by_request: Optional[bool] = join_by_request
|
||||
self.has_restricted_voice_and_video_messages: Optional[bool] = (
|
||||
has_restricted_voice_and_video_messages
|
||||
)
|
||||
self.active_usernames: Tuple[str, ...] = parse_sequence_arg(active_usernames)
|
||||
self.emoji_status_custom_emoji_id: Optional[str] = emoji_status_custom_emoji_id
|
||||
self.emoji_status_expiration_date: Optional[datetime] = emoji_status_expiration_date
|
||||
self.has_aggressive_anti_spam_enabled: Optional[bool] = (
|
||||
has_aggressive_anti_spam_enabled
|
||||
)
|
||||
self.has_hidden_members: Optional[bool] = has_hidden_members
|
||||
self.available_reactions: Optional[Tuple[ReactionType, ...]] = parse_sequence_arg(
|
||||
available_reactions
|
||||
)
|
||||
self.accent_color_id: Optional[int] = accent_color_id
|
||||
self.background_custom_emoji_id: Optional[str] = background_custom_emoji_id
|
||||
self.profile_accent_color_id: Optional[int] = profile_accent_color_id
|
||||
self.profile_background_custom_emoji_id: Optional[str] = (
|
||||
profile_background_custom_emoji_id
|
||||
)
|
||||
self.unrestrict_boost_count: Optional[int] = unrestrict_boost_count
|
||||
self.custom_emoji_sticker_set_name: Optional[str] = custom_emoji_sticker_set_name
|
||||
self.birthdate: Optional[Birthdate] = birthdate
|
||||
self.personal_chat: Optional[Chat] = personal_chat
|
||||
self.business_intro: Optional[BusinessIntro] = business_intro
|
||||
self.business_location: Optional[BusinessLocation] = business_location
|
||||
self.business_opening_hours: Optional[BusinessOpeningHours] = business_opening_hours
|
||||
|
||||
self._freeze()
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatFullInfo"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["emoji_status_expiration_date"] = from_timestamp(
|
||||
data.get("emoji_status_expiration_date"), tzinfo=loc_tzinfo
|
||||
)
|
||||
|
||||
data["photo"] = ChatPhoto.de_json(data.get("photo"), bot)
|
||||
|
||||
from telegram import ( # pylint: disable=import-outside-toplevel
|
||||
BusinessIntro,
|
||||
BusinessLocation,
|
||||
BusinessOpeningHours,
|
||||
Message,
|
||||
)
|
||||
|
||||
data["pinned_message"] = Message.de_json(data.get("pinned_message"), bot)
|
||||
data["permissions"] = ChatPermissions.de_json(data.get("permissions"), bot)
|
||||
data["location"] = ChatLocation.de_json(data.get("location"), bot)
|
||||
data["available_reactions"] = ReactionType.de_list(data.get("available_reactions"), bot)
|
||||
data["birthdate"] = Birthdate.de_json(data.get("birthdate"), bot)
|
||||
data["personal_chat"] = Chat.de_json(data.get("personal_chat"), bot)
|
||||
data["business_intro"] = BusinessIntro.de_json(data.get("business_intro"), bot)
|
||||
data["business_location"] = BusinessLocation.de_json(data.get("business_location"), bot)
|
||||
data["business_opening_hours"] = BusinessOpeningHours.de_json(
|
||||
data.get("business_opening_hours"), bot
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
|
|
@ -160,6 +160,9 @@ class InputMediaAnimation(InputMedia):
|
|||
optional): |thumbdocstringnopath|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.ANIMATION`.
|
||||
|
@ -184,9 +187,19 @@ class InputMediaAnimation(InputMedia):
|
|||
thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
"""
|
||||
|
||||
__slots__ = ("duration", "has_spoiler", "height", "thumbnail", "width")
|
||||
__slots__ = (
|
||||
"duration",
|
||||
"has_spoiler",
|
||||
"height",
|
||||
"show_caption_above_media",
|
||||
"thumbnail",
|
||||
"width",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -200,6 +213,7 @@ class InputMediaAnimation(InputMedia):
|
|||
filename: Optional[str] = None,
|
||||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -229,6 +243,7 @@ class InputMediaAnimation(InputMedia):
|
|||
self.height: Optional[int] = height
|
||||
self.duration: Optional[int] = duration
|
||||
self.has_spoiler: Optional[bool] = has_spoiler
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
|
||||
|
||||
class InputMediaPhoto(InputMedia):
|
||||
|
@ -260,6 +275,9 @@ class InputMediaPhoto(InputMedia):
|
|||
with a spoiler animation.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.PHOTO`.
|
||||
|
@ -278,9 +296,15 @@ class InputMediaPhoto(InputMedia):
|
|||
spoiler animation.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
"""
|
||||
|
||||
__slots__ = ("has_spoiler",)
|
||||
__slots__ = (
|
||||
"has_spoiler",
|
||||
"show_caption_above_media",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -290,6 +314,7 @@ class InputMediaPhoto(InputMedia):
|
|||
caption_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
filename: Optional[str] = None,
|
||||
has_spoiler: Optional[bool] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -307,6 +332,7 @@ class InputMediaPhoto(InputMedia):
|
|||
|
||||
with self._unfrozen():
|
||||
self.has_spoiler: Optional[bool] = has_spoiler
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
|
||||
|
||||
class InputMediaVideo(InputMedia):
|
||||
|
@ -359,6 +385,9 @@ class InputMediaVideo(InputMedia):
|
|||
optional): |thumbdocstringnopath|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.VIDEO`.
|
||||
|
@ -385,12 +414,16 @@ class InputMediaVideo(InputMedia):
|
|||
thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
|
||||
|
||||
.. versionadded:: 20.2
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"duration",
|
||||
"has_spoiler",
|
||||
"height",
|
||||
"show_caption_above_media",
|
||||
"supports_streaming",
|
||||
"thumbnail",
|
||||
"width",
|
||||
|
@ -409,6 +442,7 @@ class InputMediaVideo(InputMedia):
|
|||
filename: Optional[str] = None,
|
||||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -439,6 +473,7 @@ class InputMediaVideo(InputMedia):
|
|||
)
|
||||
self.supports_streaming: Optional[bool] = supports_streaming
|
||||
self.has_spoiler: Optional[bool] = has_spoiler
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
|
||||
|
||||
class InputMediaAudio(InputMedia):
|
||||
|
|
|
@ -313,7 +313,7 @@ class GiveawayCompleted(TelegramObject):
|
|||
|
||||
self.winner_count: int = winner_count
|
||||
self.unclaimed_prize_count: Optional[int] = unclaimed_prize_count
|
||||
self.giveaway_message: Optional["Message"] = giveaway_message
|
||||
self.giveaway_message: Optional[Message] = giveaway_message
|
||||
|
||||
self._id_attrs = (
|
||||
self.winner_count,
|
||||
|
|
|
@ -41,7 +41,8 @@ class InlineKeyboardButton(TelegramObject):
|
|||
:attr:`web_app` and :attr:`pay` are equal.
|
||||
|
||||
Note:
|
||||
* You must use exactly one of the optional fields. Mind that :attr:`callback_game` is not
|
||||
* Exactly one of the optional fields must be used to specify type of the button.
|
||||
* Mind that :attr:`callback_game` is not
|
||||
working as expected. Putting a game short name in it might, but is not guaranteed to
|
||||
work.
|
||||
* If your bot allows for arbitrary callback data, in keyboards returned in a response
|
||||
|
@ -123,11 +124,17 @@ class InlineKeyboardButton(TelegramObject):
|
|||
insert the bot's username and the specified inline query in the input field. Not
|
||||
supported for messages sent on behalf of a Telegram Business account.
|
||||
callback_game (:class:`telegram.CallbackGame`, optional): Description of the game that will
|
||||
be launched when the user presses the button. This type of button **must** always be
|
||||
the **first** button in the first row.
|
||||
pay (:obj:`bool`, optional): Specify :obj:`True`, to send a Pay button. This type of button
|
||||
**must** always be the **first** button in the first row and can only be used in
|
||||
invoice messages.
|
||||
be launched when the user presses the button
|
||||
|
||||
Note:
|
||||
This type of button **must** always be the first button in the first row.
|
||||
pay (:obj:`bool`, optional): Specify :obj:`True`, to send a Pay button.
|
||||
Substrings ``“⭐️”`` and ``“XTR”`` in the buttons's text will be replaced with a
|
||||
Telegram Star icon.
|
||||
|
||||
Note:
|
||||
This type of button **must** always be the first button in the first row and can
|
||||
only be used in invoice messages.
|
||||
switch_inline_query_chosen_chat (:obj:`telegram.SwitchInlineQueryChosenChat`, optional):
|
||||
If set, pressing the button will prompt the user to select one of their chats of the
|
||||
specified type, open that chat and insert the bot's username and the specified inline
|
||||
|
@ -186,11 +193,17 @@ class InlineKeyboardButton(TelegramObject):
|
|||
insert the bot's username and the specified inline query in the input field. Not
|
||||
supported for messages sent on behalf of a Telegram Business account.
|
||||
callback_game (:class:`telegram.CallbackGame`): Optional. Description of the game that will
|
||||
be launched when the user presses the button. This type of button **must** always be
|
||||
the **first** button in the first row.
|
||||
pay (:obj:`bool`): Optional. Specify :obj:`True`, to send a Pay button. This type of button
|
||||
**must** always be the **first** button in the first row and can only be used in
|
||||
invoice messages.
|
||||
be launched when the user presses the button.
|
||||
|
||||
Note:
|
||||
This type of button **must** always be the first button in the first row.
|
||||
pay (:obj:`bool`): Optional. Specify :obj:`True`, to send a Pay button.
|
||||
Substrings ``“⭐️”`` and ``“XTR”`` in the buttons's text will be replaced with a
|
||||
Telegram Star icon.
|
||||
|
||||
Note:
|
||||
This type of button **must** always be the first button in the first row and can
|
||||
only be used in invoice messages.
|
||||
switch_inline_query_chosen_chat (:obj:`telegram.SwitchInlineQueryChosenChat`): Optional.
|
||||
If set, pressing the button will prompt the user to select one of their chats of the
|
||||
specified type, open that chat and insert the bot's username and the specified inline
|
||||
|
|
|
@ -59,6 +59,9 @@ class InlineQueryResultCachedGif(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the gif.
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.GIF`.
|
||||
|
@ -81,6 +84,9 @@ class InlineQueryResultCachedGif(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
||||
message to be sent instead of the gif.
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
"""
|
||||
|
||||
|
@ -91,6 +97,7 @@ class InlineQueryResultCachedGif(InlineQueryResult):
|
|||
"input_message_content",
|
||||
"parse_mode",
|
||||
"reply_markup",
|
||||
"show_caption_above_media",
|
||||
"title",
|
||||
)
|
||||
|
||||
|
@ -104,6 +111,7 @@ class InlineQueryResultCachedGif(InlineQueryResult):
|
|||
input_message_content: Optional["InputMessageContent"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -119,3 +127,4 @@ class InlineQueryResultCachedGif(InlineQueryResult):
|
|||
self.caption_entities: Tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
|
|
|
@ -59,6 +59,9 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the MPEG-4 file.
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.MPEG4GIF`.
|
||||
|
@ -81,6 +84,9 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
||||
message to be sent instead of the MPEG-4 file.
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
"""
|
||||
|
||||
|
@ -91,6 +97,7 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
|
|||
"mpeg4_file_id",
|
||||
"parse_mode",
|
||||
"reply_markup",
|
||||
"show_caption_above_media",
|
||||
"title",
|
||||
)
|
||||
|
||||
|
@ -104,6 +111,7 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
|
|||
input_message_content: Optional["InputMessageContent"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -119,3 +127,4 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
|
|||
self.caption_entities: Tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
|
|
|
@ -60,6 +60,9 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the photo.
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.PHOTO`.
|
||||
|
@ -83,6 +86,9 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
||||
message to be sent instead of the photo.
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
"""
|
||||
|
||||
|
@ -94,6 +100,7 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
|
|||
"parse_mode",
|
||||
"photo_file_id",
|
||||
"reply_markup",
|
||||
"show_caption_above_media",
|
||||
"title",
|
||||
)
|
||||
|
||||
|
@ -108,6 +115,7 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
|
|||
input_message_content: Optional["InputMessageContent"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -124,3 +132,4 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
|
|||
self.caption_entities: Tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
|
|
|
@ -56,6 +56,9 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the video.
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VIDEO`.
|
||||
|
@ -79,6 +82,9 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
||||
message to be sent instead of the video.
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
"""
|
||||
|
||||
|
@ -89,6 +95,7 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
|
|||
"input_message_content",
|
||||
"parse_mode",
|
||||
"reply_markup",
|
||||
"show_caption_above_media",
|
||||
"title",
|
||||
"video_file_id",
|
||||
)
|
||||
|
@ -104,6 +111,7 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
|
|||
input_message_content: Optional["InputMessageContent"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -120,3 +128,4 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
|
|||
self.caption_entities: Tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
|
|
|
@ -78,6 +78,9 @@ class InlineQueryResultGif(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the GIF animation.
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Raises:
|
||||
:class:`ValueError`: If neither :paramref:`thumbnail_url` nor :paramref:`thumb_url` is
|
||||
|
@ -115,6 +118,9 @@ class InlineQueryResultGif(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
||||
message to be sent instead of the GIF animation.
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
"""
|
||||
|
||||
|
@ -128,6 +134,7 @@ class InlineQueryResultGif(InlineQueryResult):
|
|||
"input_message_content",
|
||||
"parse_mode",
|
||||
"reply_markup",
|
||||
"show_caption_above_media",
|
||||
"thumbnail_mime_type",
|
||||
"thumbnail_url",
|
||||
"title",
|
||||
|
@ -148,6 +155,7 @@ class InlineQueryResultGif(InlineQueryResult):
|
|||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
thumbnail_mime_type: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -168,3 +176,4 @@ class InlineQueryResultGif(InlineQueryResult):
|
|||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.thumbnail_mime_type: Optional[str] = thumbnail_mime_type
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
|
|
|
@ -80,7 +80,9 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the video animation.
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
Raises:
|
||||
:class:`ValueError`: If neither :paramref:`thumbnail_url` nor :paramref:`thumb_url` is
|
||||
supplied or if both are supplied and are not equal.
|
||||
|
@ -118,7 +120,9 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
||||
message to be sent instead of the video animation.
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
|
@ -131,6 +135,7 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
|||
"mpeg4_width",
|
||||
"parse_mode",
|
||||
"reply_markup",
|
||||
"show_caption_above_media",
|
||||
"thumbnail_mime_type",
|
||||
"thumbnail_url",
|
||||
"title",
|
||||
|
@ -151,6 +156,7 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
|||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
thumbnail_mime_type: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -171,3 +177,4 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
|||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.thumbnail_mime_type: Optional[str] = thumbnail_mime_type
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
|
|
|
@ -74,6 +74,9 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||
message to be sent instead of the photo.
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Raises:
|
||||
:class:`ValueError`: If neither :paramref:`thumbnail_url` nor :paramref:`thumb_url` is
|
||||
|
@ -105,6 +108,9 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
|||
to the message.
|
||||
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
||||
message to be sent instead of the photo.
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
"""
|
||||
|
||||
|
@ -118,6 +124,7 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
|||
"photo_url",
|
||||
"photo_width",
|
||||
"reply_markup",
|
||||
"show_caption_above_media",
|
||||
"thumbnail_url",
|
||||
"title",
|
||||
)
|
||||
|
@ -136,6 +143,7 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
|||
input_message_content: Optional["InputMessageContent"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -155,3 +163,4 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
|||
self.caption_entities: Tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
|
|
|
@ -88,6 +88,9 @@ class InlineQueryResultVideo(InlineQueryResult):
|
|||
message to be sent instead of the video. This field is required if
|
||||
``InlineQueryResultVideo`` is used to send an HTML-page as a result
|
||||
(e.g., a YouTube video).
|
||||
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Raises:
|
||||
:class:`ValueError`: If neither :paramref:`thumbnail_url` nor :paramref:`thumb_url` is
|
||||
|
@ -127,6 +130,9 @@ class InlineQueryResultVideo(InlineQueryResult):
|
|||
message to be sent instead of the video. This field is required if
|
||||
``InlineQueryResultVideo`` is used to send an HTML-page as a result
|
||||
(e.g., a YouTube video).
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
"""
|
||||
|
||||
|
@ -138,6 +144,7 @@ class InlineQueryResultVideo(InlineQueryResult):
|
|||
"mime_type",
|
||||
"parse_mode",
|
||||
"reply_markup",
|
||||
"show_caption_above_media",
|
||||
"thumbnail_url",
|
||||
"title",
|
||||
"video_duration",
|
||||
|
@ -162,6 +169,7 @@ class InlineQueryResultVideo(InlineQueryResult):
|
|||
input_message_content: Optional["InputMessageContent"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence[MessageEntity]] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -183,3 +191,4 @@ class InlineQueryResultVideo(InlineQueryResult):
|
|||
self.description: Optional[str] = description
|
||||
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
|
||||
self.input_message_content: Optional[InputMessageContent] = input_message_content
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
|
|
|
@ -49,12 +49,18 @@ class InputInvoiceMessageContent(InputMessageContent):
|
|||
:tg-const:`telegram.Invoice.MAX_PAYLOAD_LENGTH` bytes. This will not be displayed
|
||||
to the user, use for your internal processes.
|
||||
provider_token (:obj:`str`): Payment provider token, obtained via
|
||||
`@Botfather <https://t.me/Botfather>`_.
|
||||
`@Botfather <https://t.me/Botfather>`_. Pass an empty string for payments in
|
||||
|tg_stars|.
|
||||
|
||||
.. deprecated:: 21.3
|
||||
As of Bot API 7.4, this parameter is now optional and future versions of the
|
||||
library will make it optional as well.
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, see more on
|
||||
`currencies <https://core.telegram.org/bots/payments#supported-currencies>`_
|
||||
`currencies <https://core.telegram.org/bots/payments#supported-currencies>`_.
|
||||
Pass ``XTR`` for payments in |tg_stars|.
|
||||
prices (Sequence[:class:`telegram.LabeledPrice`]): Price breakdown, a list of
|
||||
components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus,
|
||||
etc.)
|
||||
etc.). Must contain exactly one item for payments in |tg_stars|.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|sequenceclassargs|
|
||||
|
@ -64,7 +70,8 @@ class InputInvoiceMessageContent(InputMessageContent):
|
|||
maximum tip of US$ 1.45 pass ``max_tip_amount = 145``. See the ``exp`` parameter in
|
||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, it
|
||||
shows the number of digits past the decimal point for each currency (2 for the majority
|
||||
of currencies). Defaults to ``0``.
|
||||
of currencies). Defaults to ``0``. Defaults to ``0``. Not supported for payments in
|
||||
|tg_stars|.
|
||||
suggested_tip_amounts (Sequence[:obj:`int`], optional): An array of suggested
|
||||
amounts of tip in the *smallest* units of the currency (integer, **not** float/double).
|
||||
At most 4 suggested tip amounts can be specified. The suggested tip amounts must be
|
||||
|
@ -85,20 +92,20 @@ class InputInvoiceMessageContent(InputMessageContent):
|
|||
photo_size (:obj:`int`, optional): Photo size.
|
||||
photo_width (:obj:`int`, optional): Photo width.
|
||||
photo_height (:obj:`int`, optional): Photo height.
|
||||
need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full name to
|
||||
complete the order.
|
||||
need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full
|
||||
name to complete the order. Ignored for payments in |tg_stars|.
|
||||
need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's
|
||||
phone number to complete the order
|
||||
phone number to complete the order. Ignored for payments in |tg_stars|.
|
||||
need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email
|
||||
address to complete the order.
|
||||
need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's
|
||||
shipping address to complete the order
|
||||
send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's phone
|
||||
number should be sent to provider.
|
||||
send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email address
|
||||
should be sent to provider.
|
||||
is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on the
|
||||
shipping method.
|
||||
address to complete the order. Ignored for payments in |tg_stars|.
|
||||
need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the
|
||||
user's shipping address to complete the order. Ignored for payments in |tg_stars|
|
||||
send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's
|
||||
phone number should be sent to provider. Ignored for payments in |tg_stars|.
|
||||
send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email
|
||||
address should be sent to provider. Ignored for payments in |tg_stars|.
|
||||
is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on
|
||||
the shipping method. Ignored for payments in |tg_stars|.
|
||||
|
||||
Attributes:
|
||||
title (:obj:`str`): Product name. :tg-const:`telegram.Invoice.MIN_TITLE_LENGTH`-
|
||||
|
@ -111,12 +118,14 @@ class InputInvoiceMessageContent(InputMessageContent):
|
|||
:tg-const:`telegram.Invoice.MAX_PAYLOAD_LENGTH` bytes. This will not be displayed
|
||||
to the user, use for your internal processes.
|
||||
provider_token (:obj:`str`): Payment provider token, obtained via
|
||||
`@Botfather <https://t.me/Botfather>`_.
|
||||
`@Botfather <https://t.me/Botfather>`_. Pass an empty string for payments in `Telegram
|
||||
Stars <https://t.me/BotNews/90>`_.
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, see more on
|
||||
`currencies <https://core.telegram.org/bots/payments#supported-currencies>`_
|
||||
`currencies <https://core.telegram.org/bots/payments#supported-currencies>`_.
|
||||
Pass ``XTR`` for payments in |tg_stars|.
|
||||
prices (Tuple[:class:`telegram.LabeledPrice`]): Price breakdown, a list of
|
||||
components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus,
|
||||
etc.)
|
||||
etc.). Must contain exactly one item for payments in |tg_stars|.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|tupleclassattrs|
|
||||
|
@ -126,7 +135,7 @@ class InputInvoiceMessageContent(InputMessageContent):
|
|||
maximum tip of US$ 1.45 ``max_tip_amount`` is ``145``. See the ``exp`` parameter in
|
||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, it
|
||||
shows the number of digits past the decimal point for each currency (2 for the majority
|
||||
of currencies). Defaults to ``0``.
|
||||
of currencies). Defaults to ``0``. Not supported for payments in |tg_stars|.
|
||||
suggested_tip_amounts (Tuple[:obj:`int`]): Optional. An array of suggested
|
||||
amounts of tip in the *smallest* units of the currency (integer, **not** float/double).
|
||||
At most 4 suggested tip amounts can be specified. The suggested tip amounts must be
|
||||
|
@ -146,19 +155,19 @@ class InputInvoiceMessageContent(InputMessageContent):
|
|||
photo_width (:obj:`int`): Optional. Photo width.
|
||||
photo_height (:obj:`int`): Optional. Photo height.
|
||||
need_name (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's full name to
|
||||
complete the order.
|
||||
complete the order. Ignored for payments in |tg_stars|.
|
||||
need_phone_number (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's
|
||||
phone number to complete the order
|
||||
phone number to complete the order. Ignored for payments in |tg_stars|.
|
||||
need_email (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's email
|
||||
address to complete the order.
|
||||
address to complete the order. Ignored for payments in |tg_stars|.
|
||||
need_shipping_address (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's
|
||||
shipping address to complete the order
|
||||
shipping address to complete the order. Ignored for payments in |tg_stars|.
|
||||
send_phone_number_to_provider (:obj:`bool`): Optional. Pass :obj:`True`, if user's phone
|
||||
number should be sent to provider.
|
||||
number should be sent to provider. Ignored for payments in |tg_stars|.
|
||||
send_email_to_provider (:obj:`bool`): Optional. Pass :obj:`True`, if user's email address
|
||||
should be sent to provider.
|
||||
should be sent to provider. Ignored for payments in |tg_stars|.
|
||||
is_flexible (:obj:`bool`): Optional. Pass :obj:`True`, if the final price depends on the
|
||||
shipping method.
|
||||
shipping method. Ignored for payments in |tg_stars|.
|
||||
|
||||
"""
|
||||
|
||||
|
@ -190,7 +199,7 @@ class InputInvoiceMessageContent(InputMessageContent):
|
|||
title: str,
|
||||
description: str,
|
||||
payload: str,
|
||||
provider_token: str,
|
||||
provider_token: Optional[str], # This arg is now optional since Bot API 7.4
|
||||
currency: str,
|
||||
prices: Sequence[LabeledPrice],
|
||||
max_tip_amount: Optional[int] = None,
|
||||
|
@ -216,7 +225,7 @@ class InputInvoiceMessageContent(InputMessageContent):
|
|||
self.title: str = title
|
||||
self.description: str = description
|
||||
self.payload: str = payload
|
||||
self.provider_token: str = provider_token
|
||||
self.provider_token: Optional[str] = provider_token
|
||||
self.currency: str = currency
|
||||
self.prices: Tuple[LabeledPrice, ...] = parse_sequence_arg(prices)
|
||||
# Optionals
|
||||
|
|
|
@ -108,7 +108,7 @@ class InputTextMessageContent(InputMessageContent):
|
|||
# Optionals
|
||||
self.parse_mode: ODVInput[str] = parse_mode
|
||||
self.entities: Tuple[MessageEntity, ...] = parse_sequence_arg(entities)
|
||||
self.link_preview_options: ODVInput["LinkPreviewOptions"] = parse_lpo_and_dwpp(
|
||||
self.link_preview_options: ODVInput[LinkPreviewOptions] = parse_lpo_and_dwpp(
|
||||
disable_web_page_preview, link_preview_options
|
||||
)
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ if TYPE_CHECKING:
|
|||
|
||||
class KeyboardButton(TelegramObject):
|
||||
"""
|
||||
This object represents one button of the reply keyboard. For simple text buttons, :obj:`str`
|
||||
This object represents one button of the reply keyboard. At most one of the optional fields
|
||||
must be used to specify type of the button. For simple text buttons, :obj:`str`
|
||||
can be used instead of this object to specify text of the button.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
|
|
|
@ -255,8 +255,8 @@ class Message(MaybeInaccessibleMessage):
|
|||
|
||||
.. versionchanged:: 20.8
|
||||
* This class is now a subclass of :class:`telegram.MaybeInaccessibleMessage`.
|
||||
* The :paramref:`pinned_message` now can be either class:`telegram.Message` or
|
||||
class:`telegram.InaccessibleMessage`.
|
||||
* The :paramref:`pinned_message` now can be either :class:`telegram.Message` or
|
||||
:class:`telegram.InaccessibleMessage`.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
||||
|
@ -328,6 +328,11 @@ class Message(MaybeInaccessibleMessage):
|
|||
|
||||
.. versionadded:: 20.8
|
||||
|
||||
effect_id (:obj:`str`, optional): Unique identifier of the message effect added to the
|
||||
message.
|
||||
|
||||
..versionadded:: 21.3
|
||||
|
||||
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): For messages with a
|
||||
Caption. Special entities like usernames, URLs, bot commands, etc. that appear in the
|
||||
caption. See :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities`
|
||||
|
@ -337,6 +342,9 @@ class Message(MaybeInaccessibleMessage):
|
|||
.. versionchanged:: 20.0
|
||||
|sequenceclassargs|
|
||||
|
||||
show_caption_above_media (:obj:`bool`, optional): |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
audio (:class:`telegram.Audio`, optional): Message is an audio file, information
|
||||
about the file.
|
||||
document (:class:`telegram.Document`, optional): Message is a general file, information
|
||||
|
@ -411,8 +419,8 @@ class Message(MaybeInaccessibleMessage):
|
|||
:attr:`reply_to_message` fields even if it is itself a reply.
|
||||
|
||||
.. versionchanged:: 20.8
|
||||
This attribute now is either class:`telegram.Message` or
|
||||
class:`telegram.InaccessibleMessage`.
|
||||
This attribute now is either :class:`telegram.Message` or
|
||||
:class:`telegram.InaccessibleMessage`.
|
||||
invoice (:class:`telegram.Invoice`, optional): Message is an invoice for a payment,
|
||||
information about the invoice.
|
||||
successful_payment (:class:`telegram.SuccessfulPayment`, optional): Message is a service
|
||||
|
@ -617,6 +625,11 @@ class Message(MaybeInaccessibleMessage):
|
|||
|
||||
.. versionadded:: 20.8
|
||||
|
||||
effect_id (:obj:`str`): Optional. Unique identifier of the message effect added to the
|
||||
message.
|
||||
|
||||
..versionadded:: 21.3
|
||||
|
||||
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. For messages with a
|
||||
Caption. Special entities like usernames, URLs, bot commands, etc. that appear in the
|
||||
caption. See :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities`
|
||||
|
@ -626,6 +639,9 @@ class Message(MaybeInaccessibleMessage):
|
|||
.. versionchanged:: 20.0
|
||||
|tupleclassattrs|
|
||||
|
||||
show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
|
||||
|
||||
.. versionadded:: 21.3
|
||||
audio (:class:`telegram.Audio`): Optional. Message is an audio file, information
|
||||
about the file.
|
||||
|
||||
|
@ -715,8 +731,8 @@ class Message(MaybeInaccessibleMessage):
|
|||
:attr:`reply_to_message` fields even if it is itself a reply.
|
||||
|
||||
.. versionchanged:: 20.8
|
||||
This attribute now is either class:`telegram.Message` or
|
||||
class:`telegram.InaccessibleMessage`.
|
||||
This attribute now is either :class:`telegram.Message` or
|
||||
:class:`telegram.InaccessibleMessage`.
|
||||
invoice (:class:`telegram.Invoice`): Optional. Message is an invoice for a payment,
|
||||
information about the invoice.
|
||||
successful_payment (:class:`telegram.SuccessfulPayment`): Optional. Message is a service
|
||||
|
@ -897,6 +913,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
"dice",
|
||||
"document",
|
||||
"edit_date",
|
||||
"effect_id",
|
||||
"entities",
|
||||
"external_reply",
|
||||
"forum_topic_closed",
|
||||
|
@ -942,6 +959,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
"sender_boost_count",
|
||||
"sender_business_bot",
|
||||
"sender_chat",
|
||||
"show_caption_above_media",
|
||||
"sticker",
|
||||
"story",
|
||||
"successful_payment",
|
||||
|
@ -1044,6 +1062,8 @@ class Message(MaybeInaccessibleMessage):
|
|||
sender_business_bot: Optional[User] = None,
|
||||
is_from_offline: Optional[bool] = None,
|
||||
chat_background_set: Optional[ChatBackground] = None,
|
||||
effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -1143,6 +1163,8 @@ class Message(MaybeInaccessibleMessage):
|
|||
self.sender_business_bot: Optional[User] = sender_business_bot
|
||||
self.is_from_offline: Optional[bool] = is_from_offline
|
||||
self.chat_background_set: Optional[ChatBackground] = chat_background_set
|
||||
self.effect_id: Optional[str] = effect_id
|
||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||
|
||||
self._effective_attachment = DEFAULT_NONE
|
||||
|
||||
|
@ -1634,6 +1656,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1698,6 +1721,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_markdown(
|
||||
|
@ -1710,6 +1734,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1780,6 +1805,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_markdown_v2(
|
||||
|
@ -1792,6 +1818,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1858,6 +1885,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_html(
|
||||
|
@ -1870,6 +1898,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1936,6 +1965,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_media_group(
|
||||
|
@ -1947,6 +1977,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2013,6 +2044,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_photo(
|
||||
|
@ -2027,6 +2059,8 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
has_spoiler: Optional[bool] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2092,6 +2126,8 @@ class Message(MaybeInaccessibleMessage):
|
|||
api_kwargs=api_kwargs,
|
||||
has_spoiler=has_spoiler,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def reply_audio(
|
||||
|
@ -2109,6 +2145,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2177,6 +2214,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
api_kwargs=api_kwargs,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_document(
|
||||
|
@ -2192,6 +2230,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2258,6 +2297,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_animation(
|
||||
|
@ -2276,6 +2316,8 @@ class Message(MaybeInaccessibleMessage):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2345,6 +2387,8 @@ class Message(MaybeInaccessibleMessage):
|
|||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def reply_sticker(
|
||||
|
@ -2356,6 +2400,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
emoji: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2416,6 +2461,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id=message_thread_id,
|
||||
emoji=emoji,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_video(
|
||||
|
@ -2435,6 +2481,8 @@ class Message(MaybeInaccessibleMessage):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2505,6 +2553,8 @@ class Message(MaybeInaccessibleMessage):
|
|||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def reply_video_note(
|
||||
|
@ -2518,6 +2568,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2582,6 +2633,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_voice(
|
||||
|
@ -2596,6 +2648,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2661,6 +2714,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_location(
|
||||
|
@ -2676,6 +2730,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2742,6 +2797,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_venue(
|
||||
|
@ -2759,6 +2815,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2827,6 +2884,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_contact(
|
||||
|
@ -2840,6 +2898,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2904,6 +2963,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_poll(
|
||||
|
@ -2927,6 +2987,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
question_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
question_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2999,6 +3060,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
business_connection_id=self.business_connection_id,
|
||||
question_parse_mode=question_parse_mode,
|
||||
question_entities=question_entities,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_dice(
|
||||
|
@ -3009,6 +3071,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3068,6 +3131,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_chat_action(
|
||||
|
@ -3122,6 +3186,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3183,6 +3248,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def reply_invoice(
|
||||
|
@ -3190,7 +3256,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
title: str,
|
||||
description: str,
|
||||
payload: str,
|
||||
provider_token: str,
|
||||
provider_token: Optional[str],
|
||||
currency: str,
|
||||
prices: Sequence["LabeledPrice"],
|
||||
start_parameter: Optional[str] = None,
|
||||
|
@ -3213,6 +3279,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3302,6 +3369,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
suggested_tip_amounts=suggested_tip_amounts,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def forward(
|
||||
|
@ -3331,7 +3399,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
Note:
|
||||
Since the release of Bot API 5.5 it can be impossible to forward messages from
|
||||
some chats. Use the attributes :attr:`telegram.Message.has_protected_content` and
|
||||
:attr:`telegram.Chat.has_protected_content` to check this.
|
||||
:attr:`telegram.ChatFullInfo.has_protected_content` to check this.
|
||||
|
||||
As a workaround, it is still possible to use :meth:`copy`. However, this
|
||||
behaviour is undocumented and might be changed by Telegram.
|
||||
|
@ -3365,6 +3433,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3409,6 +3478,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
api_kwargs=api_kwargs,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def reply_copy(
|
||||
|
@ -3423,6 +3493,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: ODVInput[int] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3486,6 +3557,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
api_kwargs=api_kwargs,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def edit_text(
|
||||
|
@ -3544,6 +3616,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
@ -3583,6 +3656,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
api_kwargs=api_kwargs,
|
||||
caption_entities=caption_entities,
|
||||
inline_message_id=None,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def edit_media(
|
||||
|
@ -4333,6 +4407,8 @@ class Message(MaybeInaccessibleMessage):
|
|||
insert = f'<a href="{escaped_text}">{escaped_text}</a>'
|
||||
elif entity.type == MessageEntity.BLOCKQUOTE:
|
||||
insert = f"<blockquote>{escaped_text}</blockquote>"
|
||||
elif entity.type == MessageEntity.EXPANDABLE_BLOCKQUOTE:
|
||||
insert = f"<blockquote expandable>{escaped_text}</blockquote>"
|
||||
elif entity.type == MessageEntity.BOLD:
|
||||
insert = f"<b>{escaped_text}</b>"
|
||||
elif entity.type == MessageEntity.ITALIC:
|
||||
|
@ -4483,11 +4559,12 @@ class Message(MaybeInaccessibleMessage):
|
|||
) -> Optional[str]:
|
||||
if version == 1:
|
||||
for entity_type in (
|
||||
MessageEntity.UNDERLINE,
|
||||
MessageEntity.STRIKETHROUGH,
|
||||
MessageEntity.SPOILER,
|
||||
MessageEntity.EXPANDABLE_BLOCKQUOTE,
|
||||
MessageEntity.BLOCKQUOTE,
|
||||
MessageEntity.CUSTOM_EMOJI,
|
||||
MessageEntity.SPOILER,
|
||||
MessageEntity.STRIKETHROUGH,
|
||||
MessageEntity.UNDERLINE,
|
||||
):
|
||||
if any(entity.type == entity_type for entity in entities):
|
||||
name = entity_type.name.title().replace("_", " ") # type:ignore[attr-defined]
|
||||
|
@ -4567,8 +4644,10 @@ class Message(MaybeInaccessibleMessage):
|
|||
insert = f"~{escaped_text}~"
|
||||
elif entity.type == MessageEntity.SPOILER:
|
||||
insert = f"||{escaped_text}||"
|
||||
elif entity.type == MessageEntity.BLOCKQUOTE:
|
||||
elif entity.type in (MessageEntity.BLOCKQUOTE, MessageEntity.EXPANDABLE_BLOCKQUOTE):
|
||||
insert = ">" + "\n>".join(escaped_text.splitlines())
|
||||
if entity.type == MessageEntity.EXPANDABLE_BLOCKQUOTE:
|
||||
insert = f"{insert}||"
|
||||
elif entity.type == MessageEntity.CUSTOM_EMOJI:
|
||||
# This should never be needed because ids are numeric but the documentation
|
||||
# specifically mentions it so here we are
|
||||
|
|
|
@ -140,50 +140,55 @@ class MessageEntity(TelegramObject):
|
|||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
MENTION: Final[str] = constants.MessageEntityType.MENTION
|
||||
""":const:`telegram.constants.MessageEntityType.MENTION`"""
|
||||
HASHTAG: Final[str] = constants.MessageEntityType.HASHTAG
|
||||
""":const:`telegram.constants.MessageEntityType.HASHTAG`"""
|
||||
CASHTAG: Final[str] = constants.MessageEntityType.CASHTAG
|
||||
""":const:`telegram.constants.MessageEntityType.CASHTAG`"""
|
||||
PHONE_NUMBER: Final[str] = constants.MessageEntityType.PHONE_NUMBER
|
||||
""":const:`telegram.constants.MessageEntityType.PHONE_NUMBER`"""
|
||||
BOT_COMMAND: Final[str] = constants.MessageEntityType.BOT_COMMAND
|
||||
""":const:`telegram.constants.MessageEntityType.BOT_COMMAND`"""
|
||||
URL: Final[str] = constants.MessageEntityType.URL
|
||||
""":const:`telegram.constants.MessageEntityType.URL`"""
|
||||
EMAIL: Final[str] = constants.MessageEntityType.EMAIL
|
||||
""":const:`telegram.constants.MessageEntityType.EMAIL`"""
|
||||
ALL_TYPES: Final[List[str]] = list(constants.MessageEntityType)
|
||||
"""List[:obj:`str`]: A list of all available message entity types."""
|
||||
BLOCKQUOTE: Final[str] = constants.MessageEntityType.BLOCKQUOTE
|
||||
""":const:`telegram.constants.MessageEntityType.BLOCKQUOTE`
|
||||
|
||||
.. versionadded:: 20.8
|
||||
"""
|
||||
BOLD: Final[str] = constants.MessageEntityType.BOLD
|
||||
""":const:`telegram.constants.MessageEntityType.BOLD`"""
|
||||
ITALIC: Final[str] = constants.MessageEntityType.ITALIC
|
||||
""":const:`telegram.constants.MessageEntityType.ITALIC`"""
|
||||
BOT_COMMAND: Final[str] = constants.MessageEntityType.BOT_COMMAND
|
||||
""":const:`telegram.constants.MessageEntityType.BOT_COMMAND`"""
|
||||
CASHTAG: Final[str] = constants.MessageEntityType.CASHTAG
|
||||
""":const:`telegram.constants.MessageEntityType.CASHTAG`"""
|
||||
CODE: Final[str] = constants.MessageEntityType.CODE
|
||||
""":const:`telegram.constants.MessageEntityType.CODE`"""
|
||||
CUSTOM_EMOJI: Final[str] = constants.MessageEntityType.CUSTOM_EMOJI
|
||||
""":const:`telegram.constants.MessageEntityType.CUSTOM_EMOJI`
|
||||
|
||||
.. versionadded:: 20.0
|
||||
"""
|
||||
EMAIL: Final[str] = constants.MessageEntityType.EMAIL
|
||||
""":const:`telegram.constants.MessageEntityType.EMAIL`"""
|
||||
EXPANDABLE_BLOCKQUOTE: Final[str] = constants.MessageEntityType.EXPANDABLE_BLOCKQUOTE
|
||||
""":const:`telegram.constants.MessageEntityType.EXPANDABLE_BLOCKQUOTE`
|
||||
|
||||
.. versionadded:: 21.3
|
||||
"""
|
||||
HASHTAG: Final[str] = constants.MessageEntityType.HASHTAG
|
||||
""":const:`telegram.constants.MessageEntityType.HASHTAG`"""
|
||||
ITALIC: Final[str] = constants.MessageEntityType.ITALIC
|
||||
""":const:`telegram.constants.MessageEntityType.ITALIC`"""
|
||||
MENTION: Final[str] = constants.MessageEntityType.MENTION
|
||||
""":const:`telegram.constants.MessageEntityType.MENTION`"""
|
||||
PHONE_NUMBER: Final[str] = constants.MessageEntityType.PHONE_NUMBER
|
||||
""":const:`telegram.constants.MessageEntityType.PHONE_NUMBER`"""
|
||||
PRE: Final[str] = constants.MessageEntityType.PRE
|
||||
""":const:`telegram.constants.MessageEntityType.PRE`"""
|
||||
SPOILER: Final[str] = constants.MessageEntityType.SPOILER
|
||||
""":const:`telegram.constants.MessageEntityType.SPOILER`
|
||||
|
||||
.. versionadded:: 13.10
|
||||
"""
|
||||
STRIKETHROUGH: Final[str] = constants.MessageEntityType.STRIKETHROUGH
|
||||
""":const:`telegram.constants.MessageEntityType.STRIKETHROUGH`"""
|
||||
TEXT_LINK: Final[str] = constants.MessageEntityType.TEXT_LINK
|
||||
""":const:`telegram.constants.MessageEntityType.TEXT_LINK`"""
|
||||
TEXT_MENTION: Final[str] = constants.MessageEntityType.TEXT_MENTION
|
||||
""":const:`telegram.constants.MessageEntityType.TEXT_MENTION`"""
|
||||
UNDERLINE: Final[str] = constants.MessageEntityType.UNDERLINE
|
||||
""":const:`telegram.constants.MessageEntityType.UNDERLINE`"""
|
||||
STRIKETHROUGH: Final[str] = constants.MessageEntityType.STRIKETHROUGH
|
||||
""":const:`telegram.constants.MessageEntityType.STRIKETHROUGH`"""
|
||||
SPOILER: Final[str] = constants.MessageEntityType.SPOILER
|
||||
""":const:`telegram.constants.MessageEntityType.SPOILER`
|
||||
|
||||
.. versionadded:: 13.10
|
||||
"""
|
||||
CUSTOM_EMOJI: Final[str] = constants.MessageEntityType.CUSTOM_EMOJI
|
||||
""":const:`telegram.constants.MessageEntityType.CUSTOM_EMOJI`
|
||||
|
||||
.. versionadded:: 20.0
|
||||
"""
|
||||
BLOCKQUOTE: Final[str] = constants.MessageEntityType.BLOCKQUOTE
|
||||
""":const:`telegram.constants.MessageEntityType.BLOCKQUOTE`
|
||||
|
||||
.. versionadded:: 20.8
|
||||
"""
|
||||
ALL_TYPES: Final[List[str]] = list(constants.MessageEntityType)
|
||||
"""List[:obj:`str`]: A list of all available message entity types."""
|
||||
URL: Final[str] = constants.MessageEntityType.URL
|
||||
""":const:`telegram.constants.MessageEntityType.URL`"""
|
||||
|
|
|
@ -37,7 +37,8 @@ class Invoice(TelegramObject):
|
|||
description (:obj:`str`): Product description.
|
||||
start_parameter (:obj:`str`): Unique bot deep-linking parameter that can be used to
|
||||
generate this invoice.
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code.
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in
|
||||
|tg_stars|.
|
||||
total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, not
|
||||
float/double). For example, for a price of US$ 1.45 pass ``amount = 145``. See the
|
||||
``exp`` parameter in
|
||||
|
@ -50,7 +51,8 @@ class Invoice(TelegramObject):
|
|||
description (:obj:`str`): Product description.
|
||||
start_parameter (:obj:`str`): Unique bot deep-linking parameter that can be used to
|
||||
generate this invoice.
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code.
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in
|
||||
|tg_stars|.
|
||||
total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, not
|
||||
float/double). For example, for a price of US$ 1.45 ``amount`` is ``145``. See the
|
||||
``exp`` parameter in
|
||||
|
|
|
@ -42,7 +42,8 @@ class PreCheckoutQuery(TelegramObject):
|
|||
Args:
|
||||
id (:obj:`str`): Unique query identifier.
|
||||
from_user (:class:`telegram.User`): User who sent the query.
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code.
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in
|
||||
|tg_stars|.
|
||||
total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, not
|
||||
float/double). For example, for a price of US$ 1.45 pass ``amount = 145``.
|
||||
See the ``exp`` parameter in
|
||||
|
@ -57,7 +58,8 @@ class PreCheckoutQuery(TelegramObject):
|
|||
Attributes:
|
||||
id (:obj:`str`): Unique query identifier.
|
||||
from_user (:class:`telegram.User`): User who sent the query.
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code.
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in
|
||||
|tg_stars|.
|
||||
total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, not
|
||||
float/double). For example, for a price of US$ 1.45 ``amount`` is ``145``.
|
||||
See the ``exp`` parameter in
|
||||
|
|
|
@ -36,7 +36,8 @@ class SuccessfulPayment(TelegramObject):
|
|||
:attr:`provider_payment_charge_id` are equal.
|
||||
|
||||
Args:
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code.
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in
|
||||
|tg_stars|.
|
||||
total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, not
|
||||
float/double). For example, for a price of US$ 1.45 pass ``amount = 145``.
|
||||
See the ``exp`` parameter in
|
||||
|
@ -51,7 +52,8 @@ class SuccessfulPayment(TelegramObject):
|
|||
provider_payment_charge_id (:obj:`str`): Provider payment identifier.
|
||||
|
||||
Attributes:
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code.
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in
|
||||
|tg_stars|.
|
||||
total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, not
|
||||
float/double). For example, for a price of US$ 1.45 ``amount`` is ``145``.
|
||||
See the ``exp`` parameter in
|
||||
|
|
|
@ -446,7 +446,7 @@ class Update(TelegramObject):
|
|||
)
|
||||
|
||||
self._effective_user: Optional[User] = None
|
||||
self._effective_sender: Optional[Union["User", "Chat"]] = None
|
||||
self._effective_sender: Optional[Union[User, Chat]] = None
|
||||
self._effective_chat: Optional[Chat] = None
|
||||
self._effective_message: Optional[Message] = None
|
||||
|
||||
|
@ -568,7 +568,7 @@ class Update(TelegramObject):
|
|||
if self._effective_sender:
|
||||
return self._effective_sender
|
||||
|
||||
sender: Optional[Union["User", "Chat"]] = None
|
||||
sender: Optional[Union[User, Chat]] = None
|
||||
|
||||
if message := (
|
||||
self.message
|
||||
|
|
|
@ -409,6 +409,7 @@ class User(TelegramObject):
|
|||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
disable_web_page_preview: Optional[bool] = None,
|
||||
|
@ -452,6 +453,7 @@ class User(TelegramObject):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def delete_message(
|
||||
|
@ -531,6 +533,8 @@ class User(TelegramObject):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -575,6 +579,8 @@ class User(TelegramObject):
|
|||
api_kwargs=api_kwargs,
|
||||
has_spoiler=has_spoiler,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def send_media_group(
|
||||
|
@ -587,6 +593,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -631,6 +638,7 @@ class User(TelegramObject):
|
|||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_audio(
|
||||
|
@ -649,6 +657,7 @@ class User(TelegramObject):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -696,6 +705,7 @@ class User(TelegramObject):
|
|||
api_kwargs=api_kwargs,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_chat_action(
|
||||
|
@ -750,6 +760,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -793,6 +804,7 @@ class User(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_dice(
|
||||
|
@ -804,6 +816,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -842,6 +855,7 @@ class User(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_document(
|
||||
|
@ -858,6 +872,7 @@ class User(TelegramObject):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -903,6 +918,7 @@ class User(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_game(
|
||||
|
@ -914,6 +930,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -952,6 +969,7 @@ class User(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_invoice(
|
||||
|
@ -959,7 +977,7 @@ class User(TelegramObject):
|
|||
title: str,
|
||||
description: str,
|
||||
payload: str,
|
||||
provider_token: str,
|
||||
provider_token: Optional[str],
|
||||
currency: str,
|
||||
prices: Sequence["LabeledPrice"],
|
||||
start_parameter: Optional[str] = None,
|
||||
|
@ -982,6 +1000,7 @@ class User(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1049,6 +1068,7 @@ class User(TelegramObject):
|
|||
suggested_tip_amounts=suggested_tip_amounts,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_location(
|
||||
|
@ -1065,6 +1085,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1110,6 +1131,7 @@ class User(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_animation(
|
||||
|
@ -1129,6 +1151,8 @@ class User(TelegramObject):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1177,6 +1201,8 @@ class User(TelegramObject):
|
|||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def send_sticker(
|
||||
|
@ -1189,6 +1215,7 @@ class User(TelegramObject):
|
|||
emoji: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1228,6 +1255,7 @@ class User(TelegramObject):
|
|||
message_thread_id=message_thread_id,
|
||||
emoji=emoji,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_video(
|
||||
|
@ -1248,6 +1276,8 @@ class User(TelegramObject):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1297,6 +1327,8 @@ class User(TelegramObject):
|
|||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def send_venue(
|
||||
|
@ -1315,6 +1347,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1362,6 +1395,7 @@ class User(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_video_note(
|
||||
|
@ -1376,6 +1410,7 @@ class User(TelegramObject):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1419,6 +1454,7 @@ class User(TelegramObject):
|
|||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_voice(
|
||||
|
@ -1434,6 +1470,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1478,6 +1515,7 @@ class User(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_poll(
|
||||
|
@ -1502,6 +1540,7 @@ class User(TelegramObject):
|
|||
business_connection_id: Optional[str] = None,
|
||||
question_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
question_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1553,6 +1592,7 @@ class User(TelegramObject):
|
|||
business_connection_id=business_connection_id,
|
||||
question_parse_mode=question_parse_mode,
|
||||
question_entities=question_entities,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_copy(
|
||||
|
@ -1567,6 +1607,7 @@ class User(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1608,6 +1649,7 @@ class User(TelegramObject):
|
|||
api_kwargs=api_kwargs,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def copy_message(
|
||||
|
@ -1622,6 +1664,7 @@ class User(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1663,6 +1706,7 @@ class User(TelegramObject):
|
|||
api_kwargs=api_kwargs,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def send_copies(
|
||||
|
@ -2101,3 +2145,35 @@ class User(TelegramObject):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def refund_star_payment(
|
||||
self,
|
||||
telegram_payment_charge_id: str,
|
||||
*,
|
||||
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.refund_star_payment(user_id=update.effective_user.id, *args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.refund_star_payment`.
|
||||
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
"""
|
||||
return await self.get_bot().refund_star_payment(
|
||||
user_id=self.id,
|
||||
telegram_payment_charge_id=telegram_payment_charge_id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
|
|
@ -194,7 +194,7 @@ def extract_tzinfo_from_defaults(bot: "Bot") -> Union[dtm.tzinfo, None]:
|
|||
If the bot has no default values, :obj:`None` is returned.
|
||||
"""
|
||||
# We don't use `ininstance(bot, ExtBot)` here so that this works
|
||||
# in `python-telegram-bot-raw` as well
|
||||
# without the job-queue extra dependencies as well
|
||||
if hasattr(bot, "defaults") and bot.defaults:
|
||||
return bot.defaults.tzinfo
|
||||
return None
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
# pylint: disable=missing-module-docstring
|
||||
from typing import Final, NamedTuple
|
||||
|
||||
__all__ = ("__bot_api_version__", "__bot_api_version_info__", "__version__", "__version_info__")
|
||||
__all__ = ("__version__", "__version_info__")
|
||||
|
||||
|
||||
class Version(NamedTuple):
|
||||
|
@ -51,15 +51,6 @@ class Version(NamedTuple):
|
|||
|
||||
|
||||
__version_info__: Final[Version] = Version(
|
||||
major=21, minor=2, micro=0, releaselevel="final", serial=0
|
||||
major=21, minor=3, micro=0, releaselevel="final", serial=0
|
||||
)
|
||||
__version__: Final[str] = str(__version_info__)
|
||||
|
||||
# # SETUP.PY MARKER
|
||||
# Lines above this line will be `exec`-cuted in setup.py. Make sure that this only contains
|
||||
# std-lib imports!
|
||||
|
||||
from telegram import constants # noqa: E402 # pylint: disable=wrong-import-position
|
||||
|
||||
__bot_api_version__: Final[str] = constants.BOT_API_VERSION
|
||||
__bot_api_version_info__: Final[constants._BotAPIVersion] = constants.BOT_API_VERSION_INFO
|
||||
|
|
|
@ -146,7 +146,7 @@ class _AccentColor(NamedTuple):
|
|||
#: :data:`telegram.__bot_api_version_info__`.
|
||||
#:
|
||||
#: .. versionadded:: 20.0
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=3)
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=4)
|
||||
#: :obj:`str`: Telegram Bot API
|
||||
#: version supported by this version of `python-telegram-bot`. Also available as
|
||||
#: :data:`telegram.__bot_api_version__`.
|
||||
|
@ -168,7 +168,8 @@ ZERO_DATE: Final[datetime.datetime] = datetime.datetime(1970, 1, 1, tzinfo=UTC)
|
|||
|
||||
|
||||
class AccentColor(Enum):
|
||||
"""This enum contains the available accent colors for :class:`telegram.Chat.accent_color_id`.
|
||||
"""This enum contains the available accent colors for
|
||||
:class:`telegram.ChatFullInfo.accent_color_id`.
|
||||
The members of this enum are named tuples with the following attributes:
|
||||
|
||||
- ``identifier`` (:obj:`int`): The identifier of the accent color.
|
||||
|
@ -1629,48 +1630,53 @@ class MessageEntityType(StringEnum):
|
|||
|
||||
__slots__ = ()
|
||||
|
||||
MENTION = "mention"
|
||||
""":obj:`str`: Message entities representing a mention."""
|
||||
HASHTAG = "hashtag"
|
||||
""":obj:`str`: Message entities representing a hashtag."""
|
||||
CASHTAG = "cashtag"
|
||||
""":obj:`str`: Message entities representing a cashtag."""
|
||||
PHONE_NUMBER = "phone_number"
|
||||
""":obj:`str`: Message entities representing a phone number."""
|
||||
BOT_COMMAND = "bot_command"
|
||||
""":obj:`str`: Message entities representing a bot command."""
|
||||
URL = "url"
|
||||
""":obj:`str`: Message entities representing a url."""
|
||||
EMAIL = "email"
|
||||
""":obj:`str`: Message entities representing a email."""
|
||||
BLOCKQUOTE = "blockquote"
|
||||
""":obj:`str`: Message entities representing a block quotation.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
"""
|
||||
BOLD = "bold"
|
||||
""":obj:`str`: Message entities representing bold text."""
|
||||
ITALIC = "italic"
|
||||
""":obj:`str`: Message entities representing italic text."""
|
||||
BOT_COMMAND = "bot_command"
|
||||
""":obj:`str`: Message entities representing a bot command."""
|
||||
CASHTAG = "cashtag"
|
||||
""":obj:`str`: Message entities representing a cashtag."""
|
||||
CODE = "code"
|
||||
""":obj:`str`: Message entities representing monowidth string."""
|
||||
CUSTOM_EMOJI = "custom_emoji"
|
||||
""":obj:`str`: Message entities representing inline custom emoji stickers.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
"""
|
||||
EMAIL = "email"
|
||||
""":obj:`str`: Message entities representing a email."""
|
||||
EXPANDABLE_BLOCKQUOTE = "expandable_blockquote"
|
||||
""":obj:`str`: Message entities representing collapsed-by-default block quotation.
|
||||
|
||||
.. versionadded:: 21.3
|
||||
"""
|
||||
HASHTAG = "hashtag"
|
||||
""":obj:`str`: Message entities representing a hashtag."""
|
||||
ITALIC = "italic"
|
||||
""":obj:`str`: Message entities representing italic text."""
|
||||
MENTION = "mention"
|
||||
""":obj:`str`: Message entities representing a mention."""
|
||||
PHONE_NUMBER = "phone_number"
|
||||
""":obj:`str`: Message entities representing a phone number."""
|
||||
PRE = "pre"
|
||||
""":obj:`str`: Message entities representing monowidth block."""
|
||||
SPOILER = "spoiler"
|
||||
""":obj:`str`: Message entities representing spoiler text."""
|
||||
STRIKETHROUGH = "strikethrough"
|
||||
""":obj:`str`: Message entities representing strikethrough text."""
|
||||
TEXT_LINK = "text_link"
|
||||
""":obj:`str`: Message entities representing clickable text URLs."""
|
||||
TEXT_MENTION = "text_mention"
|
||||
""":obj:`str`: Message entities representing text mention for users without usernames."""
|
||||
UNDERLINE = "underline"
|
||||
""":obj:`str`: Message entities representing underline text."""
|
||||
STRIKETHROUGH = "strikethrough"
|
||||
""":obj:`str`: Message entities representing strikethrough text."""
|
||||
SPOILER = "spoiler"
|
||||
""":obj:`str`: Message entities representing spoiler text."""
|
||||
CUSTOM_EMOJI = "custom_emoji"
|
||||
""":obj:`str`: Message entities representing inline custom emoji stickers.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
"""
|
||||
BLOCKQUOTE = "blockquote"
|
||||
""":obj:`str`: Message entities representing a block quotation.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
"""
|
||||
URL = "url"
|
||||
""":obj:`str`: Message entities representing a url."""
|
||||
|
||||
|
||||
class MessageLimit(IntEnum):
|
||||
|
@ -1800,6 +1806,10 @@ class MessageType(StringEnum):
|
|||
""":obj:`str`: Messages with :attr:`telegram.Message.dice`."""
|
||||
DOCUMENT = "document"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.document`."""
|
||||
EFFECT_ID = "effect_id"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.effect_id`.
|
||||
|
||||
.. versionadded:: 21.3"""
|
||||
FORUM_TOPIC_CREATED = "forum_topic_created"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.forum_topic_created`.
|
||||
|
||||
|
@ -1959,7 +1969,7 @@ class PollingLimit(IntEnum):
|
|||
|
||||
class ProfileAccentColor(Enum):
|
||||
"""This enum contains the available accent colors for
|
||||
:class:`telegram.Chat.profile_accent_color_id`.
|
||||
:class:`telegram.ChatFullInfo.profile_accent_color_id`.
|
||||
The members of this enum are named tuples with the following attributes:
|
||||
|
||||
- ``identifier`` (:obj:`int`): The identifier of the accent color.
|
||||
|
|
|
@ -251,15 +251,13 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
|||
"""
|
||||
|
||||
__slots__ = (
|
||||
( # noqa: RUF005
|
||||
"__create_task_tasks",
|
||||
"__update_fetcher_task",
|
||||
"__update_persistence_event",
|
||||
"__update_persistence_lock",
|
||||
"__update_persistence_task",
|
||||
# Allowing '__weakref__' creation here since we need it for the JobQueue
|
||||
# Uncomment if necessary - currently the __weakref__ slot is already created
|
||||
# in the AsyncContextManager base class
|
||||
# "__weakref__",
|
||||
"__stop_running_marker",
|
||||
"_chat_data",
|
||||
"_chat_ids_to_be_deleted_in_persistence",
|
||||
"_chat_ids_to_be_updated_in_persistence",
|
||||
|
@ -285,6 +283,13 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
|||
"updater",
|
||||
"user_data",
|
||||
)
|
||||
# Allowing '__weakref__' creation here since we need it for the JobQueue
|
||||
# Currently the __weakref__ slot is already created
|
||||
# in the AsyncContextManager base class for pythons < 3.13
|
||||
+ ("__weakref__",)
|
||||
if sys.version_info >= (3, 13)
|
||||
else ()
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self: "Application[BT, CCT, UD, CD, BD, JQ]",
|
||||
|
|
|
@ -593,6 +593,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
link_preview_options: ODVInput["LinkPreviewOptions"] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -624,6 +625,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
if isinstance(result, Message):
|
||||
self._insert_callback_data(result)
|
||||
|
@ -798,6 +800,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -828,6 +831,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def copy_messages(
|
||||
|
@ -1146,7 +1150,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
title: str,
|
||||
description: str,
|
||||
payload: str,
|
||||
provider_token: str,
|
||||
provider_token: Optional[str],
|
||||
currency: str,
|
||||
prices: Sequence["LabeledPrice"],
|
||||
max_tip_amount: Optional[int] = None,
|
||||
|
@ -1506,6 +1510,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
@ -1527,6 +1532,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def edit_message_live_location(
|
||||
|
@ -2379,6 +2385,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2415,6 +2423,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
business_connection_id=business_connection_id,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
message_effect_id=message_effect_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def send_audio(
|
||||
|
@ -2434,6 +2444,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2469,6 +2480,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_chat_action(
|
||||
|
@ -2510,6 +2522,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2541,6 +2554,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
pool_timeout=pool_timeout,
|
||||
business_connection_id=business_connection_id,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_dice(
|
||||
|
@ -2553,6 +2567,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2579,6 +2594,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_document(
|
||||
|
@ -2596,6 +2612,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2629,6 +2646,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_game(
|
||||
|
@ -2641,6 +2659,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2667,6 +2686,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_invoice(
|
||||
|
@ -2675,7 +2695,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
title: str,
|
||||
description: str,
|
||||
payload: str,
|
||||
provider_token: str,
|
||||
provider_token: Optional[str],
|
||||
currency: str,
|
||||
prices: Sequence["LabeledPrice"],
|
||||
start_parameter: Optional[str] = None,
|
||||
|
@ -2698,6 +2718,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2743,6 +2764,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_location(
|
||||
|
@ -2760,6 +2782,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2793,6 +2816,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
business_connection_id=business_connection_id,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_media_group(
|
||||
|
@ -2806,6 +2830,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2837,6 +2862,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
business_connection_id=business_connection_id,
|
||||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_message(
|
||||
|
@ -2852,6 +2878,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
disable_web_page_preview: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2883,6 +2910,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
link_preview_options=link_preview_options,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_photo(
|
||||
|
@ -2899,6 +2927,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2931,6 +2961,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
message_effect_id=message_effect_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def send_poll(
|
||||
|
@ -2956,6 +2988,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
business_connection_id: Optional[str] = None,
|
||||
question_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
question_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2995,6 +3028,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
question_parse_mode=question_parse_mode,
|
||||
question_entities=question_entities,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_sticker(
|
||||
|
@ -3008,6 +3042,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
emoji: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3035,6 +3070,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
pool_timeout=pool_timeout,
|
||||
emoji=emoji,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_venue(
|
||||
|
@ -3054,6 +3090,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3089,6 +3126,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_video(
|
||||
|
@ -3110,6 +3148,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
show_caption_above_media: Optional[bool] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3147,6 +3187,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
message_effect_id=message_effect_id,
|
||||
show_caption_above_media=show_caption_above_media,
|
||||
)
|
||||
|
||||
async def send_video_note(
|
||||
|
@ -3162,6 +3204,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3193,6 +3236,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def send_voice(
|
||||
|
@ -3209,6 +3253,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
message_effect_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3241,6 +3286,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
business_connection_id=business_connection_id,
|
||||
message_effect_id=message_effect_id,
|
||||
)
|
||||
|
||||
async def set_chat_administrator_custom_title(
|
||||
|
@ -4111,6 +4157,28 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def refund_star_payment(
|
||||
self,
|
||||
user_id: int,
|
||||
telegram_payment_charge_id: str,
|
||||
*,
|
||||
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,
|
||||
rate_limit_args: Optional[RLARGS] = None,
|
||||
) -> bool:
|
||||
return await super().refund_star_payment(
|
||||
user_id=user_id,
|
||||
telegram_payment_charge_id=telegram_payment_charge_id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
# updated camelCase aliases
|
||||
getMe = get_me
|
||||
sendMessage = send_message
|
||||
|
@ -4232,3 +4300,4 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
setMessageReaction = set_message_reaction
|
||||
getBusinessConnection = get_business_connection
|
||||
replaceStickerInSet = replace_sticker_in_set
|
||||
refundStarPayment = refund_star_payment
|
||||
|
|
|
@ -21,8 +21,9 @@ from typing import Final, Optional, TypeVar
|
|||
|
||||
from telegram import Update
|
||||
from telegram._utils.defaultvalue import DEFAULT_TRUE
|
||||
from telegram._utils.types import DVType
|
||||
from telegram._utils.types import SCT, DVType
|
||||
from telegram.ext._handlers.basehandler import BaseHandler
|
||||
from telegram.ext._utils._update_parsing import parse_chat_id
|
||||
from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
|
||||
RT = TypeVar("RT")
|
||||
|
@ -58,6 +59,9 @@ class ChatMemberHandler(BaseHandler[Update, CCT]):
|
|||
:meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`.
|
||||
|
||||
.. seealso:: :wiki:`Concurrency`
|
||||
chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters chat member updates from
|
||||
specified chat ID(s) only.
|
||||
.. versionadded:: 21.3
|
||||
|
||||
Attributes:
|
||||
callback (:term:`coroutine function`): The callback function for this handler.
|
||||
|
@ -70,7 +74,10 @@ class ChatMemberHandler(BaseHandler[Update, CCT]):
|
|||
|
||||
"""
|
||||
|
||||
__slots__ = ("chat_member_types",)
|
||||
__slots__ = (
|
||||
"_chat_ids",
|
||||
"chat_member_types",
|
||||
)
|
||||
MY_CHAT_MEMBER: Final[int] = -1
|
||||
""":obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`."""
|
||||
CHAT_MEMBER: Final[int] = 0
|
||||
|
@ -84,10 +91,12 @@ class ChatMemberHandler(BaseHandler[Update, CCT]):
|
|||
callback: HandlerCallback[Update, CCT, RT],
|
||||
chat_member_types: int = MY_CHAT_MEMBER,
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
chat_id: Optional[SCT[int]] = None,
|
||||
):
|
||||
super().__init__(callback, block=block)
|
||||
|
||||
self.chat_member_types: Optional[int] = chat_member_types
|
||||
self._chat_ids = parse_chat_id(chat_id)
|
||||
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handler's :attr:`callback`.
|
||||
|
@ -99,12 +108,18 @@ class ChatMemberHandler(BaseHandler[Update, CCT]):
|
|||
:obj:`bool`
|
||||
|
||||
"""
|
||||
if isinstance(update, Update):
|
||||
if not isinstance(update, Update):
|
||||
return False
|
||||
if not (update.my_chat_member or update.chat_member):
|
||||
return False
|
||||
if (
|
||||
self._chat_ids
|
||||
and update.effective_chat
|
||||
and update.effective_chat.id not in self._chat_ids
|
||||
):
|
||||
return False
|
||||
if self.chat_member_types == self.ANY_CHAT_MEMBER:
|
||||
return True
|
||||
if self.chat_member_types == self.CHAT_MEMBER:
|
||||
return bool(update.chat_member)
|
||||
return bool(update.my_chat_member)
|
||||
return False
|
||||
|
|
|
@ -46,6 +46,7 @@ __all__ = (
|
|||
"CHAT",
|
||||
"COMMAND",
|
||||
"CONTACT",
|
||||
"EFFECT_ID",
|
||||
"FORWARDED",
|
||||
"GAME",
|
||||
"GIVEAWAY",
|
||||
|
@ -1338,6 +1339,19 @@ class Document:
|
|||
"""Use as ``filters.Document.ZIP``."""
|
||||
|
||||
|
||||
class _EffectId(MessageFilter):
|
||||
__slots__ = ()
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.effect_id)
|
||||
|
||||
|
||||
EFFECT_ID = _EffectId(name="filters.EFFECT_ID")
|
||||
"""Messages that contain :attr:`telegram.Message.effect_id`.
|
||||
|
||||
.. versionadded:: 21.3"""
|
||||
|
||||
|
||||
class Entity(MessageFilter):
|
||||
"""
|
||||
Filters messages to only allow those which have a :class:`telegram.MessageEntity`
|
||||
|
|
|
@ -4,7 +4,7 @@ Testing in PTB
|
|||
|
||||
PTB uses `pytest`_ for testing. To run the tests, you need to
|
||||
have pytest installed along with a few other dependencies. You can find the list of dependencies
|
||||
in the ``requirements-dev.txt`` file in the root of the repository.
|
||||
in the ``pyproject.toml`` file in the root of the repository.
|
||||
|
||||
Running tests
|
||||
=============
|
||||
|
|
|
@ -219,6 +219,7 @@ class TestAnimationWithRequest(TestAnimationBase):
|
|||
protect_content=True,
|
||||
thumbnail=thumb_file,
|
||||
has_spoiler=True,
|
||||
show_caption_above_media=True,
|
||||
)
|
||||
|
||||
assert isinstance(message.animation, Animation)
|
||||
|
@ -232,6 +233,7 @@ class TestAnimationWithRequest(TestAnimationBase):
|
|||
assert message.animation.thumbnail.width == self.width
|
||||
assert message.animation.thumbnail.height == self.height
|
||||
assert message.has_protected_content
|
||||
assert message.show_caption_above_media
|
||||
try:
|
||||
assert message.has_media_spoiler
|
||||
except AssertionError:
|
||||
|
|
|
@ -58,6 +58,7 @@ def input_media_video(class_thumb_file):
|
|||
thumbnail=class_thumb_file,
|
||||
supports_streaming=TestInputMediaVideoBase.supports_streaming,
|
||||
has_spoiler=TestInputMediaVideoBase.has_spoiler,
|
||||
show_caption_above_media=TestInputMediaVideoBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
|
@ -69,6 +70,7 @@ def input_media_photo():
|
|||
parse_mode=TestInputMediaPhotoBase.parse_mode,
|
||||
caption_entities=TestInputMediaPhotoBase.caption_entities,
|
||||
has_spoiler=TestInputMediaPhotoBase.has_spoiler,
|
||||
show_caption_above_media=TestInputMediaPhotoBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
|
@ -84,6 +86,7 @@ def input_media_animation(class_thumb_file):
|
|||
thumbnail=class_thumb_file,
|
||||
duration=TestInputMediaAnimationBase.duration,
|
||||
has_spoiler=TestInputMediaAnimationBase.has_spoiler,
|
||||
show_caption_above_media=TestInputMediaAnimationBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
|
@ -124,6 +127,7 @@ class TestInputMediaVideoBase:
|
|||
supports_streaming = True
|
||||
caption_entities = [MessageEntity(MessageEntity.BOLD, 0, 2)]
|
||||
has_spoiler = True
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInputMediaVideoWithoutRequest(TestInputMediaVideoBase):
|
||||
|
@ -145,6 +149,7 @@ class TestInputMediaVideoWithoutRequest(TestInputMediaVideoBase):
|
|||
assert input_media_video.supports_streaming == self.supports_streaming
|
||||
assert isinstance(input_media_video.thumbnail, InputFile)
|
||||
assert input_media_video.has_spoiler == self.has_spoiler
|
||||
assert input_media_video.show_caption_above_media == self.show_caption_above_media
|
||||
|
||||
def test_caption_entities_always_tuple(self):
|
||||
input_media_video = InputMediaVideo(self.media)
|
||||
|
@ -164,6 +169,10 @@ class TestInputMediaVideoWithoutRequest(TestInputMediaVideoBase):
|
|||
]
|
||||
assert input_media_video_dict["supports_streaming"] == input_media_video.supports_streaming
|
||||
assert input_media_video_dict["has_spoiler"] == input_media_video.has_spoiler
|
||||
assert (
|
||||
input_media_video_dict["show_caption_above_media"]
|
||||
== input_media_video.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_with_video(self, video):
|
||||
# fixture found in test_video
|
||||
|
@ -217,6 +226,7 @@ class TestInputMediaPhotoBase:
|
|||
parse_mode = "Markdown"
|
||||
caption_entities = [MessageEntity(MessageEntity.BOLD, 0, 2)]
|
||||
has_spoiler = True
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInputMediaPhotoWithoutRequest(TestInputMediaPhotoBase):
|
||||
|
@ -233,6 +243,7 @@ class TestInputMediaPhotoWithoutRequest(TestInputMediaPhotoBase):
|
|||
assert input_media_photo.parse_mode == self.parse_mode
|
||||
assert input_media_photo.caption_entities == tuple(self.caption_entities)
|
||||
assert input_media_photo.has_spoiler == self.has_spoiler
|
||||
assert input_media_photo.show_caption_above_media == self.show_caption_above_media
|
||||
|
||||
def test_caption_entities_always_tuple(self):
|
||||
input_media_photo = InputMediaPhoto(self.media)
|
||||
|
@ -248,6 +259,10 @@ class TestInputMediaPhotoWithoutRequest(TestInputMediaPhotoBase):
|
|||
ce.to_dict() for ce in input_media_photo.caption_entities
|
||||
]
|
||||
assert input_media_photo_dict["has_spoiler"] == input_media_photo.has_spoiler
|
||||
assert (
|
||||
input_media_photo_dict["show_caption_above_media"]
|
||||
== input_media_photo.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_with_photo(self, photo):
|
||||
# fixture found in test_photo
|
||||
|
@ -278,6 +293,7 @@ class TestInputMediaAnimationBase:
|
|||
height = 30
|
||||
duration = 1
|
||||
has_spoiler = True
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInputMediaAnimationWithoutRequest(TestInputMediaAnimationBase):
|
||||
|
@ -295,6 +311,7 @@ class TestInputMediaAnimationWithoutRequest(TestInputMediaAnimationBase):
|
|||
assert input_media_animation.caption_entities == tuple(self.caption_entities)
|
||||
assert isinstance(input_media_animation.thumbnail, InputFile)
|
||||
assert input_media_animation.has_spoiler == self.has_spoiler
|
||||
assert input_media_animation.show_caption_above_media == self.show_caption_above_media
|
||||
|
||||
def test_caption_entities_always_tuple(self):
|
||||
input_media_animation = InputMediaAnimation(self.media)
|
||||
|
@ -313,6 +330,10 @@ class TestInputMediaAnimationWithoutRequest(TestInputMediaAnimationBase):
|
|||
assert input_media_animation_dict["height"] == input_media_animation.height
|
||||
assert input_media_animation_dict["duration"] == input_media_animation.duration
|
||||
assert input_media_animation_dict["has_spoiler"] == input_media_animation.has_spoiler
|
||||
assert (
|
||||
input_media_animation_dict["show_caption_above_media"]
|
||||
== input_media_animation.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_with_animation(self, animation):
|
||||
# fixture found in test_animation
|
||||
|
|
|
@ -219,6 +219,7 @@ class TestPhotoWithRequest(TestPhotoBase):
|
|||
protect_content=True,
|
||||
parse_mode="Markdown",
|
||||
has_spoiler=True,
|
||||
show_caption_above_media=True,
|
||||
)
|
||||
|
||||
assert isinstance(message.photo[-2], PhotoSize)
|
||||
|
@ -236,6 +237,7 @@ class TestPhotoWithRequest(TestPhotoBase):
|
|||
assert message.caption == self.caption.replace("*", "")
|
||||
assert message.has_protected_content
|
||||
assert message.has_media_spoiler
|
||||
assert message.show_caption_above_media
|
||||
|
||||
async def test_send_photo_parse_mode_markdown(self, bot, chat_id, photo_file):
|
||||
message = await bot.send_photo(
|
||||
|
|
|
@ -232,6 +232,7 @@ class TestVideoWithRequest(TestVideoBase):
|
|||
parse_mode="Markdown",
|
||||
thumbnail=thumb_file,
|
||||
has_spoiler=True,
|
||||
show_caption_above_media=True,
|
||||
)
|
||||
|
||||
assert isinstance(message.video, Video)
|
||||
|
@ -253,6 +254,7 @@ class TestVideoWithRequest(TestVideoBase):
|
|||
assert message.video.file_name == self.file_name
|
||||
assert message.has_protected_content
|
||||
assert message.has_media_spoiler
|
||||
assert message.show_caption_above_media
|
||||
|
||||
async def test_get_and_download(self, bot, video, chat_id, tmp_file):
|
||||
new_file = await bot.get_file(video.file_id)
|
||||
|
|
|
@ -40,6 +40,7 @@ def inline_query_result_cached_gif():
|
|||
caption_entities=TestInlineQueryResultCachedGifBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedGifBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedGifBase.reply_markup,
|
||||
show_caption_above_media=TestInlineQueryResultCachedGifBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
|
@ -53,6 +54,7 @@ class TestInlineQueryResultCachedGifBase:
|
|||
caption_entities = [MessageEntity(MessageEntity.ITALIC, 0, 7)]
|
||||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedGifWithoutRequest(TestInlineQueryResultCachedGifBase):
|
||||
|
@ -75,6 +77,10 @@ class TestInlineQueryResultCachedGifWithoutRequest(TestInlineQueryResultCachedGi
|
|||
== self.input_message_content.to_dict()
|
||||
)
|
||||
assert inline_query_result_cached_gif.reply_markup.to_dict() == self.reply_markup.to_dict()
|
||||
assert (
|
||||
inline_query_result_cached_gif.show_caption_above_media
|
||||
== self.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_caption_entities_always_tuple(self):
|
||||
result = InlineQueryResultCachedGif(self.id_, self.gif_file_id)
|
||||
|
@ -110,6 +116,10 @@ class TestInlineQueryResultCachedGifWithoutRequest(TestInlineQueryResultCachedGi
|
|||
inline_query_result_cached_gif_dict["reply_markup"]
|
||||
== inline_query_result_cached_gif.reply_markup.to_dict()
|
||||
)
|
||||
assert (
|
||||
inline_query_result_cached_gif_dict["show_caption_above_media"]
|
||||
== inline_query_result_cached_gif.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultCachedGif(self.id_, self.gif_file_id)
|
||||
|
|
|
@ -40,6 +40,7 @@ def inline_query_result_cached_mpeg4_gif():
|
|||
caption_entities=TestInlineQueryResultCachedMpeg4GifBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedMpeg4GifBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedMpeg4GifBase.reply_markup,
|
||||
show_caption_above_media=TestInlineQueryResultCachedMpeg4GifBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
|
@ -53,6 +54,7 @@ class TestInlineQueryResultCachedMpeg4GifBase:
|
|||
caption_entities = [MessageEntity(MessageEntity.ITALIC, 0, 7)]
|
||||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedMpeg4GifWithoutRequest(TestInlineQueryResultCachedMpeg4GifBase):
|
||||
|
@ -80,6 +82,10 @@ class TestInlineQueryResultCachedMpeg4GifWithoutRequest(TestInlineQueryResultCac
|
|||
inline_query_result_cached_mpeg4_gif.reply_markup.to_dict()
|
||||
== self.reply_markup.to_dict()
|
||||
)
|
||||
assert (
|
||||
inline_query_result_cached_mpeg4_gif.show_caption_above_media
|
||||
== self.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_caption_entities_always_tuple(self):
|
||||
result = InlineQueryResultCachedMpeg4Gif(self.id_, self.mpeg4_file_id)
|
||||
|
@ -124,6 +130,10 @@ class TestInlineQueryResultCachedMpeg4GifWithoutRequest(TestInlineQueryResultCac
|
|||
inline_query_result_cached_mpeg4_gif_dict["reply_markup"]
|
||||
== inline_query_result_cached_mpeg4_gif.reply_markup.to_dict()
|
||||
)
|
||||
assert (
|
||||
inline_query_result_cached_mpeg4_gif_dict["show_caption_above_media"]
|
||||
== inline_query_result_cached_mpeg4_gif.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultCachedMpeg4Gif(self.id_, self.mpeg4_file_id)
|
||||
|
|
|
@ -41,6 +41,7 @@ def inline_query_result_cached_photo():
|
|||
caption_entities=TestInlineQueryResultCachedPhotoBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedPhotoBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedPhotoBase.reply_markup,
|
||||
show_caption_above_media=TestInlineQueryResultCachedPhotoBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
|
@ -55,6 +56,7 @@ class TestInlineQueryResultCachedPhotoBase:
|
|||
caption_entities = [MessageEntity(MessageEntity.ITALIC, 0, 7)]
|
||||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedPhotoWithoutRequest(TestInlineQueryResultCachedPhotoBase):
|
||||
|
@ -80,6 +82,10 @@ class TestInlineQueryResultCachedPhotoWithoutRequest(TestInlineQueryResultCached
|
|||
assert (
|
||||
inline_query_result_cached_photo.reply_markup.to_dict() == self.reply_markup.to_dict()
|
||||
)
|
||||
assert (
|
||||
inline_query_result_cached_photo.show_caption_above_media
|
||||
== self.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_caption_entities_always_tuple(self):
|
||||
result = InlineQueryResultCachedPhoto(self.id_, self.photo_file_id)
|
||||
|
@ -124,6 +130,10 @@ class TestInlineQueryResultCachedPhotoWithoutRequest(TestInlineQueryResultCached
|
|||
inline_query_result_cached_photo_dict["reply_markup"]
|
||||
== inline_query_result_cached_photo.reply_markup.to_dict()
|
||||
)
|
||||
assert (
|
||||
inline_query_result_cached_photo_dict["show_caption_above_media"]
|
||||
== inline_query_result_cached_photo.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultCachedPhoto(self.id_, self.photo_file_id)
|
||||
|
|
|
@ -41,6 +41,7 @@ def inline_query_result_cached_video():
|
|||
description=TestInlineQueryResultCachedVideoBase.description,
|
||||
input_message_content=TestInlineQueryResultCachedVideoBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedVideoBase.reply_markup,
|
||||
show_caption_above_media=TestInlineQueryResultCachedVideoBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
|
@ -55,6 +56,7 @@ class TestInlineQueryResultCachedVideoBase:
|
|||
description = "description"
|
||||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedVideoWithoutRequest(TestInlineQueryResultCachedVideoBase):
|
||||
|
@ -80,6 +82,10 @@ class TestInlineQueryResultCachedVideoWithoutRequest(TestInlineQueryResultCached
|
|||
assert (
|
||||
inline_query_result_cached_video.reply_markup.to_dict() == self.reply_markup.to_dict()
|
||||
)
|
||||
assert (
|
||||
inline_query_result_cached_video.show_caption_above_media
|
||||
== self.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_caption_entities_always_tuple(self):
|
||||
video = InlineQueryResultCachedVideo(self.id_, self.video_file_id, self.title)
|
||||
|
@ -125,6 +131,10 @@ class TestInlineQueryResultCachedVideoWithoutRequest(TestInlineQueryResultCached
|
|||
inline_query_result_cached_video_dict["reply_markup"]
|
||||
== inline_query_result_cached_video.reply_markup.to_dict()
|
||||
)
|
||||
assert (
|
||||
inline_query_result_cached_video_dict["show_caption_above_media"]
|
||||
== inline_query_result_cached_video.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultCachedVideo(self.id_, self.video_file_id, self.title)
|
||||
|
|
|
@ -45,6 +45,7 @@ def inline_query_result_gif():
|
|||
input_message_content=TestInlineQueryResultGifBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultGifBase.reply_markup,
|
||||
thumbnail_mime_type=TestInlineQueryResultGifBase.thumbnail_mime_type,
|
||||
show_caption_above_media=TestInlineQueryResultGifBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
|
@ -63,6 +64,7 @@ class TestInlineQueryResultGifBase:
|
|||
caption_entities = [MessageEntity(MessageEntity.ITALIC, 0, 7)]
|
||||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultGifWithoutRequest(TestInlineQueryResultGifBase):
|
||||
|
@ -94,6 +96,7 @@ class TestInlineQueryResultGifWithoutRequest(TestInlineQueryResultGifBase):
|
|||
== self.input_message_content.to_dict()
|
||||
)
|
||||
assert inline_query_result_gif.reply_markup.to_dict() == self.reply_markup.to_dict()
|
||||
assert inline_query_result_gif.show_caption_above_media == self.show_caption_above_media
|
||||
|
||||
def test_to_dict(self, inline_query_result_gif):
|
||||
inline_query_result_gif_dict = inline_query_result_gif.to_dict()
|
||||
|
@ -126,6 +129,10 @@ class TestInlineQueryResultGifWithoutRequest(TestInlineQueryResultGifBase):
|
|||
inline_query_result_gif_dict["reply_markup"]
|
||||
== inline_query_result_gif.reply_markup.to_dict()
|
||||
)
|
||||
assert (
|
||||
inline_query_result_gif_dict["show_caption_above_media"]
|
||||
== inline_query_result_gif.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultGif(self.id_, self.gif_url, self.thumbnail_url)
|
||||
|
|
|
@ -45,6 +45,7 @@ def inline_query_result_mpeg4_gif():
|
|||
input_message_content=TestInlineQueryResultMpeg4GifBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultMpeg4GifBase.reply_markup,
|
||||
thumbnail_mime_type=TestInlineQueryResultMpeg4GifBase.thumbnail_mime_type,
|
||||
show_caption_above_media=TestInlineQueryResultMpeg4GifBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
|
@ -63,6 +64,7 @@ class TestInlineQueryResultMpeg4GifBase:
|
|||
caption_entities = [MessageEntity(MessageEntity.ITALIC, 0, 7)]
|
||||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultMpeg4GifWithoutRequest(TestInlineQueryResultMpeg4GifBase):
|
||||
|
@ -90,6 +92,9 @@ class TestInlineQueryResultMpeg4GifWithoutRequest(TestInlineQueryResultMpeg4GifB
|
|||
== self.input_message_content.to_dict()
|
||||
)
|
||||
assert inline_query_result_mpeg4_gif.reply_markup.to_dict() == self.reply_markup.to_dict()
|
||||
assert (
|
||||
inline_query_result_mpeg4_gif.show_caption_above_media == self.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_caption_entities_always_tuple(self):
|
||||
result = InlineQueryResultMpeg4Gif(self.id_, self.mpeg4_url, self.thumbnail_url)
|
||||
|
@ -144,6 +149,10 @@ class TestInlineQueryResultMpeg4GifWithoutRequest(TestInlineQueryResultMpeg4GifB
|
|||
inline_query_result_mpeg4_gif_dict["reply_markup"]
|
||||
== inline_query_result_mpeg4_gif.reply_markup.to_dict()
|
||||
)
|
||||
assert (
|
||||
inline_query_result_mpeg4_gif_dict["show_caption_above_media"]
|
||||
== inline_query_result_mpeg4_gif.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultMpeg4Gif(self.id_, self.mpeg4_url, self.thumbnail_url)
|
||||
|
|
|
@ -44,6 +44,7 @@ def inline_query_result_photo():
|
|||
caption_entities=TestInlineQueryResultPhotoBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultPhotoBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultPhotoBase.reply_markup,
|
||||
show_caption_above_media=TestInlineQueryResultPhotoBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
|
@ -62,6 +63,7 @@ class TestInlineQueryResultPhotoBase:
|
|||
|
||||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultPhotoWithoutRequest(TestInlineQueryResultPhotoBase):
|
||||
|
@ -88,6 +90,7 @@ class TestInlineQueryResultPhotoWithoutRequest(TestInlineQueryResultPhotoBase):
|
|||
== self.input_message_content.to_dict()
|
||||
)
|
||||
assert inline_query_result_photo.reply_markup.to_dict() == self.reply_markup.to_dict()
|
||||
assert inline_query_result_photo.show_caption_above_media == self.show_caption_above_media
|
||||
|
||||
def test_caption_entities_always_tuple(self):
|
||||
result = InlineQueryResultPhoto(self.id_, self.photo_url, self.thumbnail_url)
|
||||
|
@ -128,6 +131,10 @@ class TestInlineQueryResultPhotoWithoutRequest(TestInlineQueryResultPhotoBase):
|
|||
inline_query_result_photo_dict["reply_markup"]
|
||||
== inline_query_result_photo.reply_markup.to_dict()
|
||||
)
|
||||
assert (
|
||||
inline_query_result_photo_dict["show_caption_above_media"]
|
||||
== inline_query_result_photo.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultPhoto(self.id_, self.photo_url, self.thumbnail_url)
|
||||
|
|
|
@ -46,6 +46,7 @@ def inline_query_result_video():
|
|||
description=TestInlineQueryResultVideoBase.description,
|
||||
input_message_content=TestInlineQueryResultVideoBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultVideoBase.reply_markup,
|
||||
show_caption_above_media=TestInlineQueryResultVideoBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
|
@ -65,6 +66,7 @@ class TestInlineQueryResultVideoBase:
|
|||
description = "description"
|
||||
input_message_content = InputTextMessageContent("input_message_content")
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultVideoWithoutRequest(TestInlineQueryResultVideoBase):
|
||||
|
@ -93,6 +95,7 @@ class TestInlineQueryResultVideoWithoutRequest(TestInlineQueryResultVideoBase):
|
|||
== self.input_message_content.to_dict()
|
||||
)
|
||||
assert inline_query_result_video.reply_markup.to_dict() == self.reply_markup.to_dict()
|
||||
assert inline_query_result_video.show_caption_above_media == self.show_caption_above_media
|
||||
|
||||
def test_caption_entities_always_tuple(self):
|
||||
video = InlineQueryResultVideo(
|
||||
|
@ -140,6 +143,10 @@ class TestInlineQueryResultVideoWithoutRequest(TestInlineQueryResultVideoBase):
|
|||
inline_query_result_video_dict["reply_markup"]
|
||||
== inline_query_result_video.reply_markup.to_dict()
|
||||
)
|
||||
assert (
|
||||
inline_query_result_video_dict["show_caption_above_media"]
|
||||
== inline_query_result_video.show_caption_above_media
|
||||
)
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultVideo(
|
||||
|
|
|
@ -292,13 +292,14 @@ class TestInvoiceWithRequest(TestInvoiceBase):
|
|||
self.title,
|
||||
self.description,
|
||||
self.payload,
|
||||
provider_token,
|
||||
self.currency,
|
||||
self.prices,
|
||||
"", # using tg stars
|
||||
"XTR",
|
||||
[self.prices[0]],
|
||||
allow_sending_without_reply=custom,
|
||||
reply_to_message_id=reply_to_message.message_id,
|
||||
)
|
||||
assert message.reply_to_message is None
|
||||
assert message.invoice.currency == "XTR"
|
||||
elif default_bot.defaults.allow_sending_without_reply:
|
||||
message = await default_bot.send_invoice(
|
||||
chat_id,
|
||||
|
|
|
@ -21,7 +21,7 @@ modify behavior of the respective parent classes in order to make them easier to
|
|||
pytest framework. A common change is to allow monkeypatching of the class members by not
|
||||
enforcing slots in the subclasses."""
|
||||
from telegram import Bot, Message, User
|
||||
from telegram.ext import Application, ExtBot
|
||||
from telegram.ext import Application, ExtBot, Updater
|
||||
from tests.auxil.ci_bots import BOT_INFO_PROVIDER
|
||||
from tests.auxil.constants import PRIVATE_KEY
|
||||
from tests.auxil.envvars import TEST_WITH_OPT_DEPS
|
||||
|
@ -85,6 +85,10 @@ class PytestMessage(Message):
|
|||
pass
|
||||
|
||||
|
||||
class PytestUpdater(Updater):
|
||||
pass
|
||||
|
||||
|
||||
def make_bot(bot_info=None, **kwargs):
|
||||
"""
|
||||
Tests are executed on tg.ext.ExtBot, as that class only extends the functionality of tg.bot
|
||||
|
|
|
@ -20,6 +20,7 @@ import asyncio
|
|||
import datetime
|
||||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
from uuid import uuid4
|
||||
|
||||
|
@ -344,6 +345,5 @@ def timezone(tzinfo):
|
|||
|
||||
|
||||
@pytest.fixture()
|
||||
def tmp_file(tmp_path):
|
||||
with tmp_path / uuid4().hex as file:
|
||||
yield file
|
||||
def tmp_file(tmp_path) -> Path:
|
||||
return tmp_path / uuid4().hex
|
||||
|
|
|
@ -61,7 +61,7 @@ from tests.auxil.asyncio_helpers import call_after
|
|||
from tests.auxil.build_messages import make_message_update
|
||||
from tests.auxil.files import PROJECT_ROOT_PATH
|
||||
from tests.auxil.networking import send_webhook_message
|
||||
from tests.auxil.pytest_classes import make_bot
|
||||
from tests.auxil.pytest_classes import PytestApplication, PytestUpdater, make_bot
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
|
@ -1581,7 +1581,13 @@ class TestApplication:
|
|||
async def post_init(app: Application) -> None:
|
||||
events.append("post_init")
|
||||
|
||||
app = Application.builder().bot(one_time_bot).post_init(post_init).build()
|
||||
app = (
|
||||
Application.builder()
|
||||
.application_class(PytestApplication)
|
||||
.updater(PytestUpdater(one_time_bot, asyncio.Queue()))
|
||||
.post_init(post_init)
|
||||
.build()
|
||||
)
|
||||
app.bot._unfreeze()
|
||||
monkeypatch.setattr(app.bot, "get_updates", get_updates)
|
||||
monkeypatch.setattr(
|
||||
|
@ -1624,7 +1630,13 @@ class TestApplication:
|
|||
async def post_shutdown(app: Application) -> None:
|
||||
events.append("post_shutdown")
|
||||
|
||||
app = Application.builder().bot(one_time_bot).post_shutdown(post_shutdown).build()
|
||||
app = (
|
||||
Application.builder()
|
||||
.application_class(PytestApplication)
|
||||
.updater(PytestUpdater(one_time_bot, asyncio.Queue()))
|
||||
.post_shutdown(post_shutdown)
|
||||
.build()
|
||||
)
|
||||
app.bot._unfreeze()
|
||||
monkeypatch.setattr(app.bot, "get_updates", get_updates)
|
||||
monkeypatch.setattr(
|
||||
|
@ -1650,7 +1662,7 @@ class TestApplication:
|
|||
platform.system() == "Windows",
|
||||
reason="Can't send signals without stopping whole process on windows",
|
||||
)
|
||||
def test_run_polling_post_stop(self, bot, monkeypatch):
|
||||
def test_run_polling_post_stop(self, one_time_bot, monkeypatch):
|
||||
events = []
|
||||
|
||||
async def get_updates(*args, **kwargs):
|
||||
|
@ -1671,7 +1683,13 @@ class TestApplication:
|
|||
async def post_stop(app: Application) -> None:
|
||||
events.append("post_stop")
|
||||
|
||||
app = Application.builder().token(bot.token).post_stop(post_stop).build()
|
||||
app = (
|
||||
Application.builder()
|
||||
.application_class(PytestApplication)
|
||||
.updater(PytestUpdater(one_time_bot, asyncio.Queue()))
|
||||
.post_stop(post_stop)
|
||||
.build()
|
||||
)
|
||||
app.bot._unfreeze()
|
||||
monkeypatch.setattr(app.bot, "get_updates", get_updates)
|
||||
monkeypatch.setattr(app, "stop", call_after(app.stop, lambda _: events.append("stop")))
|
||||
|
@ -1863,7 +1881,13 @@ class TestApplication:
|
|||
async def post_init(app: Application) -> None:
|
||||
events.append("post_init")
|
||||
|
||||
app = Application.builder().bot(one_time_bot).post_init(post_init).build()
|
||||
app = (
|
||||
Application.builder()
|
||||
.post_init(post_init)
|
||||
.application_class(PytestApplication)
|
||||
.updater(PytestUpdater(one_time_bot, asyncio.Queue()))
|
||||
.build()
|
||||
)
|
||||
app.bot._unfreeze()
|
||||
monkeypatch.setattr(app.bot, "set_webhook", set_webhook)
|
||||
monkeypatch.setattr(app.bot, "delete_webhook", delete_webhook)
|
||||
|
@ -1923,7 +1947,13 @@ class TestApplication:
|
|||
async def post_shutdown(app: Application) -> None:
|
||||
events.append("post_shutdown")
|
||||
|
||||
app = Application.builder().bot(one_time_bot).post_shutdown(post_shutdown).build()
|
||||
app = (
|
||||
Application.builder()
|
||||
.application_class(PytestApplication)
|
||||
.updater(PytestUpdater(one_time_bot, asyncio.Queue()))
|
||||
.post_shutdown(post_shutdown)
|
||||
.build()
|
||||
)
|
||||
app.bot._unfreeze()
|
||||
monkeypatch.setattr(app.bot, "set_webhook", set_webhook)
|
||||
monkeypatch.setattr(app.bot, "delete_webhook", delete_webhook)
|
||||
|
@ -1960,7 +1990,7 @@ class TestApplication:
|
|||
platform.system() == "Windows",
|
||||
reason="Can't send signals without stopping whole process on windows",
|
||||
)
|
||||
def test_run_webhook_post_stop(self, bot, monkeypatch):
|
||||
def test_run_webhook_post_stop(self, one_time_bot, monkeypatch):
|
||||
events = []
|
||||
|
||||
async def delete_webhook(*args, **kwargs):
|
||||
|
@ -1987,7 +2017,13 @@ class TestApplication:
|
|||
async def post_stop(app: Application) -> None:
|
||||
events.append("post_stop")
|
||||
|
||||
app = Application.builder().token(bot.token).post_stop(post_stop).build()
|
||||
app = (
|
||||
Application.builder()
|
||||
.application_class(PytestApplication)
|
||||
.updater(PytestUpdater(one_time_bot, asyncio.Queue()))
|
||||
.post_stop(post_stop)
|
||||
.build()
|
||||
)
|
||||
app.bot._unfreeze()
|
||||
monkeypatch.setattr(app.bot, "set_webhook", set_webhook)
|
||||
monkeypatch.setattr(app.bot, "delete_webhook", delete_webhook)
|
||||
|
@ -2480,7 +2516,13 @@ class TestApplication:
|
|||
|
||||
app.create_task(task(app))
|
||||
|
||||
app = ApplicationBuilder().bot(one_time_bot).post_init(post_init).build()
|
||||
app = (
|
||||
ApplicationBuilder()
|
||||
.application_class(PytestApplication)
|
||||
.updater(PytestUpdater(one_time_bot, asyncio.Queue()))
|
||||
.post_init(post_init)
|
||||
.build()
|
||||
)
|
||||
monkeypatch.setattr(app.bot, "get_updates", get_updates)
|
||||
monkeypatch.setattr(app.bot, "set_webhook", set_webhook)
|
||||
monkeypatch.setattr(app.bot, "delete_webhook", delete_webhook)
|
||||
|
|
|
@ -144,6 +144,66 @@ class TestChatMemberHandler:
|
|||
await app.process_update(chat_member)
|
||||
assert self.test_flag == result_2
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
argnames=["allowed_types", "chat_id", "expected"],
|
||||
argvalues=[
|
||||
(ChatMemberHandler.MY_CHAT_MEMBER, None, (True, False)),
|
||||
(ChatMemberHandler.CHAT_MEMBER, None, (False, True)),
|
||||
(ChatMemberHandler.ANY_CHAT_MEMBER, None, (True, True)),
|
||||
(ChatMemberHandler.MY_CHAT_MEMBER, 1, (True, False)),
|
||||
(ChatMemberHandler.CHAT_MEMBER, 1, (False, True)),
|
||||
(ChatMemberHandler.ANY_CHAT_MEMBER, 1, (True, True)),
|
||||
(ChatMemberHandler.MY_CHAT_MEMBER, [1], (True, False)),
|
||||
(ChatMemberHandler.CHAT_MEMBER, [1], (False, True)),
|
||||
(ChatMemberHandler.ANY_CHAT_MEMBER, [1], (True, True)),
|
||||
(ChatMemberHandler.MY_CHAT_MEMBER, 2, (False, False)),
|
||||
(ChatMemberHandler.CHAT_MEMBER, 2, (False, False)),
|
||||
(ChatMemberHandler.ANY_CHAT_MEMBER, 2, (False, False)),
|
||||
(ChatMemberHandler.MY_CHAT_MEMBER, [2], (False, False)),
|
||||
(ChatMemberHandler.CHAT_MEMBER, [2], (False, False)),
|
||||
(ChatMemberHandler.ANY_CHAT_MEMBER, [2], (False, False)),
|
||||
],
|
||||
ids=[
|
||||
"MY_CHAT_MEMBER",
|
||||
"CHAT_MEMBER",
|
||||
"ANY_CHAT_MEMBER",
|
||||
"MY_CHAT_MEMBER, CHAT=1 ",
|
||||
"CHAT_MEMBER, CHAT=1",
|
||||
"ANY_CHAT_MEMBER, CHAT=1",
|
||||
"MY_CHAT_MEMBER, CHAT=[1] ",
|
||||
"CHAT_MEMBER, CHAT=[1]",
|
||||
"ANY_CHAT_MEMBER, CHAT=[1]",
|
||||
"MY_CHAT_MEMBER, CHAT=2 ",
|
||||
"CHAT_MEMBER, CHAT=2",
|
||||
"ANY_CHAT_MEMBER, CHAT=2",
|
||||
"MY_CHAT_MEMBER, CHAT=[2] ",
|
||||
"CHAT_MEMBER, CHAT=[2]",
|
||||
"ANY_CHAT_MEMBER, CHAT=[2]",
|
||||
],
|
||||
)
|
||||
async def test_chat_member_types_with_chat_id(
|
||||
self, app, chat_member_updated, chat_member, expected, allowed_types, chat_id
|
||||
):
|
||||
result_1, result_2 = expected
|
||||
|
||||
handler = ChatMemberHandler(
|
||||
self.callback, chat_member_types=allowed_types, chat_id=chat_id
|
||||
)
|
||||
app.add_handler(handler)
|
||||
|
||||
async with app:
|
||||
assert handler.check_update(chat_member) == result_1
|
||||
await app.process_update(chat_member)
|
||||
assert self.test_flag == result_1
|
||||
|
||||
self.test_flag = False
|
||||
chat_member.my_chat_member = None
|
||||
chat_member.chat_member = chat_member_updated
|
||||
|
||||
assert handler.check_update(chat_member) == result_2
|
||||
await app.process_update(chat_member)
|
||||
assert self.test_flag == result_2
|
||||
|
||||
def test_other_update_types(self, false_update):
|
||||
handler = ChatMemberHandler(self.callback)
|
||||
assert not handler.check_update(false_update)
|
||||
|
|
|
@ -1107,6 +1107,11 @@ class TestFilters:
|
|||
update.message.game = "test"
|
||||
assert filters.GAME.check_update(update)
|
||||
|
||||
def test_filters_effect_id(self, update):
|
||||
assert not filters.EFFECT_ID.check_update(update)
|
||||
update.message.effect_id = "test"
|
||||
assert filters.EFFECT_ID.check_update(update)
|
||||
|
||||
def test_entities_filter(self, update, message_entity):
|
||||
update.message.entities = [message_entity]
|
||||
assert filters.Entity(message_entity.type).check_update(update)
|
||||
|
|
|
@ -47,6 +47,7 @@ from telegram.request._httpxrequest import HTTPXRequest
|
|||
from telegram.request._requestparameter import RequestParameter
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
from tests.auxil.envvars import TEST_WITH_OPT_DEPS
|
||||
from tests.auxil.networking import NonchalantHttpxRequest
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
# We only need mixed_rqs fixture, but it uses the others, so pytest needs us to import them as well
|
||||
|
@ -72,7 +73,7 @@ def mocker_factory(
|
|||
|
||||
@pytest.fixture()
|
||||
async def httpx_request():
|
||||
async with HTTPXRequest() as rq:
|
||||
async with NonchalantHttpxRequest() as rq:
|
||||
yield rq
|
||||
|
||||
|
||||
|
@ -137,7 +138,7 @@ class TestRequestWithoutRequest:
|
|||
async def shutdown():
|
||||
self.test_flag.append("stop")
|
||||
|
||||
httpx_request = HTTPXRequest()
|
||||
httpx_request = NonchalantHttpxRequest()
|
||||
|
||||
monkeypatch.setattr(httpx_request, "initialize", initialize)
|
||||
monkeypatch.setattr(httpx_request, "shutdown", shutdown)
|
||||
|
@ -154,7 +155,7 @@ class TestRequestWithoutRequest:
|
|||
async def shutdown():
|
||||
self.test_flag = "stop"
|
||||
|
||||
httpx_request = HTTPXRequest()
|
||||
httpx_request = NonchalantHttpxRequest()
|
||||
|
||||
monkeypatch.setattr(httpx_request, "initialize", initialize)
|
||||
monkeypatch.setattr(httpx_request, "shutdown", shutdown)
|
||||
|
@ -545,7 +546,7 @@ class TestHTTPXRequestWithoutRequest:
|
|||
async def aclose(*args):
|
||||
self.test_flag.append("stop")
|
||||
|
||||
httpx_request = HTTPXRequest()
|
||||
httpx_request = NonchalantHttpxRequest()
|
||||
|
||||
monkeypatch.setattr(httpx_request, "initialize", initialize)
|
||||
monkeypatch.setattr(httpx.AsyncClient, "aclose", aclose)
|
||||
|
@ -562,7 +563,7 @@ class TestHTTPXRequestWithoutRequest:
|
|||
async def aclose(*args):
|
||||
self.test_flag = "stop"
|
||||
|
||||
httpx_request = HTTPXRequest()
|
||||
httpx_request = NonchalantHttpxRequest()
|
||||
|
||||
monkeypatch.setattr(httpx_request, "initialize", initialize)
|
||||
monkeypatch.setattr(httpx.AsyncClient, "aclose", aclose)
|
||||
|
|
|
@ -97,7 +97,7 @@ from tests.auxil.bot_method_checks import check_defaults_handling
|
|||
from tests.auxil.ci_bots import FALLBACKS
|
||||
from tests.auxil.envvars import GITHUB_ACTION, TEST_WITH_OPT_DEPS
|
||||
from tests.auxil.files import data_file
|
||||
from tests.auxil.networking import expect_bad_request
|
||||
from tests.auxil.networking import NonchalantHttpxRequest, expect_bad_request
|
||||
from tests.auxil.pytest_classes import PytestBot, PytestExtBot, make_bot
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
@ -252,7 +252,7 @@ class TestBotWithoutRequest:
|
|||
async def stop(*args, **kwargs):
|
||||
self.test_flag.append("stop")
|
||||
|
||||
temp_bot = PytestBot(token=bot.token)
|
||||
temp_bot = PytestBot(token=bot.token, request=NonchalantHttpxRequest())
|
||||
orig_stop = temp_bot.request.shutdown
|
||||
|
||||
try:
|
||||
|
@ -2179,6 +2179,16 @@ class TestBotWithoutRequest:
|
|||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_message(2, "text", business_connection_id=42)
|
||||
|
||||
async def test_message_effect_id_argument(self, bot, monkeypatch):
|
||||
"""We can't test every single method easily, so we just test one. Our linting will catch
|
||||
any unused args with the others."""
|
||||
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.parameters.get("message_effect_id") == 42
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_message(2, "text", message_effect_id=42)
|
||||
|
||||
async def test_get_business_connection(self, bot, monkeypatch):
|
||||
bci = "42"
|
||||
user = User(1, "first", False)
|
||||
|
@ -2212,6 +2222,17 @@ class TestBotWithoutRequest:
|
|||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
assert await bot.send_chat_action(chat_id, "action", 1, 3)
|
||||
|
||||
async def test_refund_star_payment(self, bot, monkeypatch):
|
||||
# can't make actual request so we just test that the correct data is passed
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return (
|
||||
request_data.parameters.get("user_id") == 42
|
||||
and request_data.parameters.get("telegram_payment_charge_id") == "37"
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.refund_star_payment(42, "37")
|
||||
|
||||
|
||||
class TestBotWithRequest:
|
||||
"""
|
||||
|
@ -2813,9 +2834,11 @@ class TestBotWithRequest:
|
|||
caption="new_caption",
|
||||
chat_id=media_message.chat_id,
|
||||
message_id=media_message.message_id,
|
||||
show_caption_above_media=False,
|
||||
)
|
||||
|
||||
assert message.caption == "new_caption"
|
||||
assert not message.show_caption_above_media
|
||||
|
||||
async def test_edit_message_caption_entities(self, bot, media_message):
|
||||
test_string = "Italic Bold Code"
|
||||
|
@ -3804,6 +3827,7 @@ class TestBotWithRequest:
|
|||
parse_mode=ParseMode.HTML,
|
||||
reply_to_message_id=media_message.message_id,
|
||||
reply_markup=keyboard,
|
||||
show_caption_above_media=False,
|
||||
)
|
||||
# we send a temp message which replies to the returned message id in order to get a
|
||||
# message object
|
||||
|
|
|
@ -17,31 +17,12 @@
|
|||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
import datetime
|
||||
import warnings
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import (
|
||||
Birthdate,
|
||||
Bot,
|
||||
BusinessIntro,
|
||||
BusinessLocation,
|
||||
BusinessOpeningHours,
|
||||
BusinessOpeningHoursInterval,
|
||||
Chat,
|
||||
ChatLocation,
|
||||
ChatPermissions,
|
||||
Location,
|
||||
ReactionTypeCustomEmoji,
|
||||
ReactionTypeEmoji,
|
||||
User,
|
||||
)
|
||||
from telegram._chat import _deprecated_attrs
|
||||
from telegram._utils.datetime import UTC, to_timestamp
|
||||
from telegram import Bot, Chat, ChatPermissions, ReactionTypeEmoji, User
|
||||
from telegram.constants import ChatAction, ChatType, ReactionEmoji
|
||||
from telegram.helpers import escape_markdown
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
from tests.auxil.bot_method_checks import (
|
||||
check_defaults_handling,
|
||||
check_shortcut_call,
|
||||
|
@ -57,37 +38,7 @@ def chat(bot):
|
|||
title=TestChatBase.title,
|
||||
type=TestChatBase.type_,
|
||||
username=TestChatBase.username,
|
||||
sticker_set_name=TestChatBase.sticker_set_name,
|
||||
can_set_sticker_set=TestChatBase.can_set_sticker_set,
|
||||
permissions=TestChatBase.permissions,
|
||||
slow_mode_delay=TestChatBase.slow_mode_delay,
|
||||
bio=TestChatBase.bio,
|
||||
linked_chat_id=TestChatBase.linked_chat_id,
|
||||
location=TestChatBase.location,
|
||||
has_private_forwards=True,
|
||||
has_protected_content=True,
|
||||
has_visible_history=True,
|
||||
join_to_send_messages=True,
|
||||
join_by_request=True,
|
||||
has_restricted_voice_and_video_messages=True,
|
||||
is_forum=True,
|
||||
active_usernames=TestChatBase.active_usernames,
|
||||
emoji_status_custom_emoji_id=TestChatBase.emoji_status_custom_emoji_id,
|
||||
emoji_status_expiration_date=TestChatBase.emoji_status_expiration_date,
|
||||
has_aggressive_anti_spam_enabled=TestChatBase.has_aggressive_anti_spam_enabled,
|
||||
has_hidden_members=TestChatBase.has_hidden_members,
|
||||
available_reactions=TestChatBase.available_reactions,
|
||||
accent_color_id=TestChatBase.accent_color_id,
|
||||
background_custom_emoji_id=TestChatBase.background_custom_emoji_id,
|
||||
profile_accent_color_id=TestChatBase.profile_accent_color_id,
|
||||
profile_background_custom_emoji_id=TestChatBase.profile_background_custom_emoji_id,
|
||||
unrestrict_boost_count=TestChatBase.unrestrict_boost_count,
|
||||
custom_emoji_sticker_set_name=TestChatBase.custom_emoji_sticker_set_name,
|
||||
business_intro=TestChatBase.business_intro,
|
||||
business_location=TestChatBase.business_location,
|
||||
business_opening_hours=TestChatBase.business_opening_hours,
|
||||
birthdate=Birthdate(1, 1),
|
||||
personal_chat=TestChatBase.personal_chat,
|
||||
first_name=TestChatBase.first_name,
|
||||
last_name=TestChatBase.last_name,
|
||||
)
|
||||
|
@ -101,48 +52,7 @@ class TestChatBase:
|
|||
title = "ToledosPalaceBot - Group"
|
||||
type_ = "group"
|
||||
username = "username"
|
||||
all_members_are_administrators = False
|
||||
sticker_set_name = "stickers"
|
||||
can_set_sticker_set = False
|
||||
permissions = ChatPermissions(
|
||||
can_send_messages=True,
|
||||
can_change_info=False,
|
||||
can_invite_users=True,
|
||||
)
|
||||
slow_mode_delay = 30
|
||||
bio = "I'm a Barbie Girl in a Barbie World"
|
||||
linked_chat_id = 11880
|
||||
location = ChatLocation(Location(123, 456), "Barbie World")
|
||||
has_protected_content = True
|
||||
has_visible_history = True
|
||||
has_private_forwards = True
|
||||
join_to_send_messages = True
|
||||
join_by_request = True
|
||||
has_restricted_voice_and_video_messages = True
|
||||
is_forum = True
|
||||
active_usernames = ["These", "Are", "Usernames!"]
|
||||
emoji_status_custom_emoji_id = "VeryUniqueCustomEmojiID"
|
||||
emoji_status_expiration_date = datetime.datetime.now(tz=UTC).replace(microsecond=0)
|
||||
has_aggressive_anti_spam_enabled = True
|
||||
has_hidden_members = True
|
||||
available_reactions = [
|
||||
ReactionTypeEmoji(ReactionEmoji.THUMBS_DOWN),
|
||||
ReactionTypeCustomEmoji("custom_emoji_id"),
|
||||
]
|
||||
business_intro = BusinessIntro("Title", "Description", None)
|
||||
business_location = BusinessLocation("Address", Location(123, 456))
|
||||
business_opening_hours = BusinessOpeningHours(
|
||||
"Country/City",
|
||||
[BusinessOpeningHoursInterval(opening, opening + 60) for opening in (0, 24 * 60)],
|
||||
)
|
||||
accent_color_id = 1
|
||||
background_custom_emoji_id = "background_custom_emoji_id"
|
||||
profile_accent_color_id = 2
|
||||
profile_background_custom_emoji_id = "profile_background_custom_emoji_id"
|
||||
unrestrict_boost_count = 100
|
||||
custom_emoji_sticker_set_name = "custom_emoji_sticker_set_name"
|
||||
birthdate = Birthdate(1, 1)
|
||||
personal_chat = Chat(3, "private", "private")
|
||||
first_name = "first"
|
||||
last_name = "last"
|
||||
|
||||
|
@ -159,40 +69,7 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
"title": self.title,
|
||||
"type": self.type_,
|
||||
"username": self.username,
|
||||
"all_members_are_administrators": self.all_members_are_administrators,
|
||||
"sticker_set_name": self.sticker_set_name,
|
||||
"can_set_sticker_set": self.can_set_sticker_set,
|
||||
"permissions": self.permissions.to_dict(),
|
||||
"slow_mode_delay": self.slow_mode_delay,
|
||||
"bio": self.bio,
|
||||
"business_intro": self.business_intro.to_dict(),
|
||||
"business_location": self.business_location.to_dict(),
|
||||
"business_opening_hours": self.business_opening_hours.to_dict(),
|
||||
"has_protected_content": self.has_protected_content,
|
||||
"has_visible_history": self.has_visible_history,
|
||||
"has_private_forwards": self.has_private_forwards,
|
||||
"linked_chat_id": self.linked_chat_id,
|
||||
"location": self.location.to_dict(),
|
||||
"join_to_send_messages": self.join_to_send_messages,
|
||||
"join_by_request": self.join_by_request,
|
||||
"has_restricted_voice_and_video_messages": (
|
||||
self.has_restricted_voice_and_video_messages
|
||||
),
|
||||
"is_forum": self.is_forum,
|
||||
"active_usernames": self.active_usernames,
|
||||
"emoji_status_custom_emoji_id": self.emoji_status_custom_emoji_id,
|
||||
"emoji_status_expiration_date": to_timestamp(self.emoji_status_expiration_date),
|
||||
"has_aggressive_anti_spam_enabled": self.has_aggressive_anti_spam_enabled,
|
||||
"has_hidden_members": self.has_hidden_members,
|
||||
"available_reactions": [reaction.to_dict() for reaction in self.available_reactions],
|
||||
"accent_color_id": self.accent_color_id,
|
||||
"background_custom_emoji_id": self.background_custom_emoji_id,
|
||||
"profile_accent_color_id": self.profile_accent_color_id,
|
||||
"profile_background_custom_emoji_id": self.profile_background_custom_emoji_id,
|
||||
"unrestrict_boost_count": self.unrestrict_boost_count,
|
||||
"custom_emoji_sticker_set_name": self.custom_emoji_sticker_set_name,
|
||||
"birthdate": self.birthdate.to_dict(),
|
||||
"personal_chat": self.personal_chat.to_dict(),
|
||||
"first_name": self.first_name,
|
||||
"last_name": self.last_name,
|
||||
}
|
||||
|
@ -202,76 +79,10 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
assert chat.title == self.title
|
||||
assert chat.type == self.type_
|
||||
assert chat.username == self.username
|
||||
assert chat.sticker_set_name == self.sticker_set_name
|
||||
assert chat.can_set_sticker_set == self.can_set_sticker_set
|
||||
assert chat.permissions == self.permissions
|
||||
assert chat.slow_mode_delay == self.slow_mode_delay
|
||||
assert chat.bio == self.bio
|
||||
assert chat.business_intro == self.business_intro
|
||||
assert chat.business_location == self.business_location
|
||||
assert chat.business_opening_hours == self.business_opening_hours
|
||||
assert chat.has_protected_content == self.has_protected_content
|
||||
assert chat.has_visible_history == self.has_visible_history
|
||||
assert chat.has_private_forwards == self.has_private_forwards
|
||||
assert chat.linked_chat_id == self.linked_chat_id
|
||||
assert chat.location.location == self.location.location
|
||||
assert chat.location.address == self.location.address
|
||||
assert chat.join_to_send_messages == self.join_to_send_messages
|
||||
assert chat.join_by_request == self.join_by_request
|
||||
assert (
|
||||
chat.has_restricted_voice_and_video_messages
|
||||
== self.has_restricted_voice_and_video_messages
|
||||
)
|
||||
assert chat.api_kwargs == {
|
||||
"all_members_are_administrators": self.all_members_are_administrators
|
||||
}
|
||||
assert chat.is_forum == self.is_forum
|
||||
assert chat.active_usernames == tuple(self.active_usernames)
|
||||
assert chat.emoji_status_custom_emoji_id == self.emoji_status_custom_emoji_id
|
||||
assert chat.emoji_status_expiration_date == (self.emoji_status_expiration_date)
|
||||
assert chat.has_aggressive_anti_spam_enabled == self.has_aggressive_anti_spam_enabled
|
||||
assert chat.has_hidden_members == self.has_hidden_members
|
||||
assert chat.available_reactions == tuple(self.available_reactions)
|
||||
assert chat.accent_color_id == self.accent_color_id
|
||||
assert chat.background_custom_emoji_id == self.background_custom_emoji_id
|
||||
assert chat.profile_accent_color_id == self.profile_accent_color_id
|
||||
assert chat.profile_background_custom_emoji_id == self.profile_background_custom_emoji_id
|
||||
assert chat.unrestrict_boost_count == self.unrestrict_boost_count
|
||||
assert chat.custom_emoji_sticker_set_name == self.custom_emoji_sticker_set_name
|
||||
assert chat.birthdate == self.birthdate
|
||||
assert chat.personal_chat == self.personal_chat
|
||||
assert chat.first_name == self.first_name
|
||||
assert chat.last_name == self.last_name
|
||||
|
||||
def test_de_json_localization(self, bot, raw_bot, tz_bot):
|
||||
json_dict = {
|
||||
"id": self.id_,
|
||||
"type": self.type_,
|
||||
"emoji_status_expiration_date": to_timestamp(self.emoji_status_expiration_date),
|
||||
}
|
||||
chat_bot = Chat.de_json(json_dict, bot)
|
||||
chat_bot_raw = Chat.de_json(json_dict, raw_bot)
|
||||
chat_bot_tz = Chat.de_json(json_dict, tz_bot)
|
||||
|
||||
# comparing utcoffsets because comparing tzinfo objects is not reliable
|
||||
emoji_expire_offset = chat_bot_tz.emoji_status_expiration_date.utcoffset()
|
||||
emoji_expire_offset_tz = tz_bot.defaults.tzinfo.utcoffset(
|
||||
chat_bot_tz.emoji_status_expiration_date.replace(tzinfo=None)
|
||||
)
|
||||
|
||||
assert chat_bot.emoji_status_expiration_date.tzinfo == UTC
|
||||
assert chat_bot_raw.emoji_status_expiration_date.tzinfo == UTC
|
||||
assert emoji_expire_offset_tz == emoji_expire_offset
|
||||
|
||||
def test_always_tuples_attributes(self):
|
||||
chat = Chat(
|
||||
id=123,
|
||||
title="title",
|
||||
type=Chat.PRIVATE,
|
||||
)
|
||||
assert isinstance(chat.active_usernames, tuple)
|
||||
assert chat.active_usernames == ()
|
||||
|
||||
def test_to_dict(self, chat):
|
||||
chat_dict = chat.to_dict()
|
||||
|
||||
|
@ -280,67 +91,10 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
assert chat_dict["title"] == chat.title
|
||||
assert chat_dict["type"] == chat.type
|
||||
assert chat_dict["username"] == chat.username
|
||||
assert chat_dict["permissions"] == chat.permissions.to_dict()
|
||||
assert chat_dict["slow_mode_delay"] == chat.slow_mode_delay
|
||||
assert chat_dict["bio"] == chat.bio
|
||||
assert chat_dict["business_intro"] == chat.business_intro.to_dict()
|
||||
assert chat_dict["business_location"] == chat.business_location.to_dict()
|
||||
assert chat_dict["business_opening_hours"] == chat.business_opening_hours.to_dict()
|
||||
assert chat_dict["has_private_forwards"] == chat.has_private_forwards
|
||||
assert chat_dict["has_protected_content"] == chat.has_protected_content
|
||||
assert chat_dict["has_visible_history"] == chat.has_visible_history
|
||||
assert chat_dict["linked_chat_id"] == chat.linked_chat_id
|
||||
assert chat_dict["location"] == chat.location.to_dict()
|
||||
assert chat_dict["join_to_send_messages"] == chat.join_to_send_messages
|
||||
assert chat_dict["join_by_request"] == chat.join_by_request
|
||||
assert (
|
||||
chat_dict["has_restricted_voice_and_video_messages"]
|
||||
== chat.has_restricted_voice_and_video_messages
|
||||
)
|
||||
assert chat_dict["is_forum"] == chat.is_forum
|
||||
assert chat_dict["active_usernames"] == list(chat.active_usernames)
|
||||
assert chat_dict["emoji_status_custom_emoji_id"] == chat.emoji_status_custom_emoji_id
|
||||
assert chat_dict["emoji_status_expiration_date"] == to_timestamp(
|
||||
chat.emoji_status_expiration_date
|
||||
)
|
||||
assert (
|
||||
chat_dict["has_aggressive_anti_spam_enabled"] == chat.has_aggressive_anti_spam_enabled
|
||||
)
|
||||
assert chat_dict["has_hidden_members"] == chat.has_hidden_members
|
||||
assert chat_dict["available_reactions"] == [
|
||||
reaction.to_dict() for reaction in chat.available_reactions
|
||||
]
|
||||
assert chat_dict["accent_color_id"] == chat.accent_color_id
|
||||
assert chat_dict["background_custom_emoji_id"] == chat.background_custom_emoji_id
|
||||
assert chat_dict["profile_accent_color_id"] == chat.profile_accent_color_id
|
||||
assert (
|
||||
chat_dict["profile_background_custom_emoji_id"]
|
||||
== chat.profile_background_custom_emoji_id
|
||||
)
|
||||
assert chat_dict["custom_emoji_sticker_set_name"] == chat.custom_emoji_sticker_set_name
|
||||
assert chat_dict["unrestrict_boost_count"] == chat.unrestrict_boost_count
|
||||
assert chat_dict["birthdate"] == chat.birthdate.to_dict()
|
||||
assert chat_dict["personal_chat"] == chat.personal_chat.to_dict()
|
||||
assert chat_dict["first_name"] == chat.first_name
|
||||
assert chat_dict["last_name"] == chat.last_name
|
||||
|
||||
def test_deprecated_attributes(self, chat):
|
||||
for depr_attr in _deprecated_attrs:
|
||||
with pytest.warns(PTBDeprecationWarning, match="deprecated and will only be accessib"):
|
||||
getattr(chat, depr_attr)
|
||||
with warnings.catch_warnings(): # No warning should be raised
|
||||
warnings.simplefilter("error")
|
||||
chat.id
|
||||
chat.first_name
|
||||
|
||||
def test_deprecated_arguments(self):
|
||||
for depr_attr in _deprecated_attrs:
|
||||
with pytest.warns(PTBDeprecationWarning, match="deprecated and will only be availabl"):
|
||||
Chat(1, "type", **{depr_attr: "1"})
|
||||
with warnings.catch_warnings(): # No warning should be raised
|
||||
warnings.simplefilter("error")
|
||||
Chat(1, "type", first_name="first_name")
|
||||
|
||||
def test_enum_init(self):
|
||||
chat = Chat(id=1, type="foo")
|
||||
assert chat.type == "foo"
|
||||
|
@ -957,8 +711,8 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
return from_chat_id and message_id and chat_id
|
||||
|
||||
assert check_shortcut_signature(Chat.send_copy, Bot.copy_message, ["chat_id"], [])
|
||||
assert await check_shortcut_call(chat.copy_message, chat.get_bot(), "copy_message")
|
||||
assert await check_defaults_handling(chat.copy_message, chat.get_bot())
|
||||
assert await check_shortcut_call(chat.send_copy, chat.get_bot(), "copy_message")
|
||||
assert await check_defaults_handling(chat.send_copy, chat.get_bot())
|
||||
|
||||
monkeypatch.setattr(chat.get_bot(), "copy_message", make_assertion)
|
||||
assert await chat.send_copy(from_chat_id="test_copy", message_id=42)
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import datetime
|
||||
import warnings
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -35,7 +34,6 @@ from telegram import (
|
|||
ReactionTypeCustomEmoji,
|
||||
ReactionTypeEmoji,
|
||||
)
|
||||
from telegram._chat import _deprecated_attrs
|
||||
from telegram._utils.datetime import UTC, to_timestamp
|
||||
from telegram.constants import ReactionEmoji
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
@ -44,19 +42,19 @@ from tests.auxil.slots import mro_slots
|
|||
@pytest.fixture(scope="module")
|
||||
def chat_full_info(bot):
|
||||
chat = ChatFullInfo(
|
||||
TestChatInfoBase.id_,
|
||||
type=TestChatInfoBase.type_,
|
||||
accent_color_id=TestChatInfoBase.accent_color_id,
|
||||
max_reaction_count=TestChatInfoBase.max_reaction_count,
|
||||
title=TestChatInfoBase.title,
|
||||
username=TestChatInfoBase.username,
|
||||
sticker_set_name=TestChatInfoBase.sticker_set_name,
|
||||
can_set_sticker_set=TestChatInfoBase.can_set_sticker_set,
|
||||
permissions=TestChatInfoBase.permissions,
|
||||
slow_mode_delay=TestChatInfoBase.slow_mode_delay,
|
||||
bio=TestChatInfoBase.bio,
|
||||
linked_chat_id=TestChatInfoBase.linked_chat_id,
|
||||
location=TestChatInfoBase.location,
|
||||
TestChatFullInfoBase.id_,
|
||||
type=TestChatFullInfoBase.type_,
|
||||
accent_color_id=TestChatFullInfoBase.accent_color_id,
|
||||
max_reaction_count=TestChatFullInfoBase.max_reaction_count,
|
||||
title=TestChatFullInfoBase.title,
|
||||
username=TestChatFullInfoBase.username,
|
||||
sticker_set_name=TestChatFullInfoBase.sticker_set_name,
|
||||
can_set_sticker_set=TestChatFullInfoBase.can_set_sticker_set,
|
||||
permissions=TestChatFullInfoBase.permissions,
|
||||
slow_mode_delay=TestChatFullInfoBase.slow_mode_delay,
|
||||
bio=TestChatFullInfoBase.bio,
|
||||
linked_chat_id=TestChatFullInfoBase.linked_chat_id,
|
||||
location=TestChatFullInfoBase.location,
|
||||
has_private_forwards=True,
|
||||
has_protected_content=True,
|
||||
has_visible_history=True,
|
||||
|
@ -64,35 +62,37 @@ def chat_full_info(bot):
|
|||
join_by_request=True,
|
||||
has_restricted_voice_and_video_messages=True,
|
||||
is_forum=True,
|
||||
active_usernames=TestChatInfoBase.active_usernames,
|
||||
emoji_status_custom_emoji_id=TestChatInfoBase.emoji_status_custom_emoji_id,
|
||||
emoji_status_expiration_date=TestChatInfoBase.emoji_status_expiration_date,
|
||||
has_aggressive_anti_spam_enabled=TestChatInfoBase.has_aggressive_anti_spam_enabled,
|
||||
has_hidden_members=TestChatInfoBase.has_hidden_members,
|
||||
available_reactions=TestChatInfoBase.available_reactions,
|
||||
background_custom_emoji_id=TestChatInfoBase.background_custom_emoji_id,
|
||||
profile_accent_color_id=TestChatInfoBase.profile_accent_color_id,
|
||||
profile_background_custom_emoji_id=TestChatInfoBase.profile_background_custom_emoji_id,
|
||||
unrestrict_boost_count=TestChatInfoBase.unrestrict_boost_count,
|
||||
custom_emoji_sticker_set_name=TestChatInfoBase.custom_emoji_sticker_set_name,
|
||||
business_intro=TestChatInfoBase.business_intro,
|
||||
business_location=TestChatInfoBase.business_location,
|
||||
business_opening_hours=TestChatInfoBase.business_opening_hours,
|
||||
active_usernames=TestChatFullInfoBase.active_usernames,
|
||||
emoji_status_custom_emoji_id=TestChatFullInfoBase.emoji_status_custom_emoji_id,
|
||||
emoji_status_expiration_date=TestChatFullInfoBase.emoji_status_expiration_date,
|
||||
has_aggressive_anti_spam_enabled=TestChatFullInfoBase.has_aggressive_anti_spam_enabled,
|
||||
has_hidden_members=TestChatFullInfoBase.has_hidden_members,
|
||||
available_reactions=TestChatFullInfoBase.available_reactions,
|
||||
background_custom_emoji_id=TestChatFullInfoBase.background_custom_emoji_id,
|
||||
profile_accent_color_id=TestChatFullInfoBase.profile_accent_color_id,
|
||||
profile_background_custom_emoji_id=TestChatFullInfoBase.profile_background_custom_emoji_id,
|
||||
unrestrict_boost_count=TestChatFullInfoBase.unrestrict_boost_count,
|
||||
custom_emoji_sticker_set_name=TestChatFullInfoBase.custom_emoji_sticker_set_name,
|
||||
business_intro=TestChatFullInfoBase.business_intro,
|
||||
business_location=TestChatFullInfoBase.business_location,
|
||||
business_opening_hours=TestChatFullInfoBase.business_opening_hours,
|
||||
birthdate=Birthdate(1, 1),
|
||||
personal_chat=TestChatInfoBase.personal_chat,
|
||||
personal_chat=TestChatFullInfoBase.personal_chat,
|
||||
first_name="first_name",
|
||||
last_name="last_name",
|
||||
)
|
||||
chat.set_bot(bot)
|
||||
chat._unfreeze()
|
||||
return chat
|
||||
|
||||
|
||||
class TestChatInfoBase:
|
||||
# Shortcut methods are tested in test_chat.py.
|
||||
class TestChatFullInfoBase:
|
||||
id_ = -28767330
|
||||
max_reaction_count = 2
|
||||
title = "ToledosPalaceBot - Group"
|
||||
type_ = "group"
|
||||
username = "username"
|
||||
all_members_are_administrators = False
|
||||
sticker_set_name = "stickers"
|
||||
can_set_sticker_set = False
|
||||
permissions = ChatPermissions(
|
||||
|
@ -134,13 +134,16 @@ class TestChatInfoBase:
|
|||
custom_emoji_sticker_set_name = "custom_emoji_sticker_set_name"
|
||||
birthdate = Birthdate(1, 1)
|
||||
personal_chat = Chat(3, "private", "private")
|
||||
first_name = "first_name"
|
||||
last_name = "last_name"
|
||||
|
||||
|
||||
class TestChatWithoutRequest(TestChatInfoBase):
|
||||
class TestChatFullInfoWithoutRequest(TestChatFullInfoBase):
|
||||
def test_slot_behaviour(self, chat_full_info):
|
||||
cfi = chat_full_info
|
||||
for attr in cfi.__slots__:
|
||||
assert getattr(cfi, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
|
||||
assert len(mro_slots(cfi)) == len(set(mro_slots(cfi))), "duplicate slot"
|
||||
|
||||
def test_de_json(self, bot):
|
||||
|
@ -151,7 +154,6 @@ class TestChatWithoutRequest(TestChatInfoBase):
|
|||
"accent_color_id": self.accent_color_id,
|
||||
"max_reaction_count": self.max_reaction_count,
|
||||
"username": self.username,
|
||||
"all_members_are_administrators": self.all_members_are_administrators,
|
||||
"sticker_set_name": self.sticker_set_name,
|
||||
"can_set_sticker_set": self.can_set_sticker_set,
|
||||
"permissions": self.permissions.to_dict(),
|
||||
|
@ -184,26 +186,134 @@ class TestChatWithoutRequest(TestChatInfoBase):
|
|||
"custom_emoji_sticker_set_name": self.custom_emoji_sticker_set_name,
|
||||
"birthdate": self.birthdate.to_dict(),
|
||||
"personal_chat": self.personal_chat.to_dict(),
|
||||
"first_name": self.first_name,
|
||||
"last_name": self.last_name,
|
||||
}
|
||||
cfi = ChatFullInfo.de_json(json_dict, bot)
|
||||
assert cfi.id == self.id_
|
||||
assert cfi.title == self.title
|
||||
assert cfi.type == self.type_
|
||||
assert cfi.username == self.username
|
||||
assert cfi.sticker_set_name == self.sticker_set_name
|
||||
assert cfi.can_set_sticker_set == self.can_set_sticker_set
|
||||
assert cfi.permissions == self.permissions
|
||||
assert cfi.slow_mode_delay == self.slow_mode_delay
|
||||
assert cfi.bio == self.bio
|
||||
assert cfi.business_intro == self.business_intro
|
||||
assert cfi.business_location == self.business_location
|
||||
assert cfi.business_opening_hours == self.business_opening_hours
|
||||
assert cfi.has_protected_content == self.has_protected_content
|
||||
assert cfi.has_visible_history == self.has_visible_history
|
||||
assert cfi.has_private_forwards == self.has_private_forwards
|
||||
assert cfi.linked_chat_id == self.linked_chat_id
|
||||
assert cfi.location.location == self.location.location
|
||||
assert cfi.location.address == self.location.address
|
||||
assert cfi.join_to_send_messages == self.join_to_send_messages
|
||||
assert cfi.join_by_request == self.join_by_request
|
||||
assert (
|
||||
cfi.has_restricted_voice_and_video_messages
|
||||
== self.has_restricted_voice_and_video_messages
|
||||
)
|
||||
assert cfi.is_forum == self.is_forum
|
||||
assert cfi.active_usernames == tuple(self.active_usernames)
|
||||
assert cfi.emoji_status_custom_emoji_id == self.emoji_status_custom_emoji_id
|
||||
assert cfi.emoji_status_expiration_date == (self.emoji_status_expiration_date)
|
||||
assert cfi.has_aggressive_anti_spam_enabled == self.has_aggressive_anti_spam_enabled
|
||||
assert cfi.has_hidden_members == self.has_hidden_members
|
||||
assert cfi.available_reactions == tuple(self.available_reactions)
|
||||
assert cfi.accent_color_id == self.accent_color_id
|
||||
assert cfi.background_custom_emoji_id == self.background_custom_emoji_id
|
||||
assert cfi.profile_accent_color_id == self.profile_accent_color_id
|
||||
assert cfi.profile_background_custom_emoji_id == self.profile_background_custom_emoji_id
|
||||
assert cfi.unrestrict_boost_count == self.unrestrict_boost_count
|
||||
assert cfi.custom_emoji_sticker_set_name == self.custom_emoji_sticker_set_name
|
||||
assert cfi.birthdate == self.birthdate
|
||||
assert cfi.personal_chat == self.personal_chat
|
||||
assert cfi.first_name == self.first_name
|
||||
assert cfi.last_name == self.last_name
|
||||
assert cfi.max_reaction_count == self.max_reaction_count
|
||||
|
||||
def test_de_json_localization(self, bot, raw_bot, tz_bot):
|
||||
json_dict = {
|
||||
"id": self.id_,
|
||||
"type": self.type_,
|
||||
"accent_color_id": self.accent_color_id,
|
||||
"max_reaction_count": self.max_reaction_count,
|
||||
"emoji_status_expiration_date": to_timestamp(self.emoji_status_expiration_date),
|
||||
}
|
||||
cfi_bot = ChatFullInfo.de_json(json_dict, bot)
|
||||
cfi_bot_raw = ChatFullInfo.de_json(json_dict, raw_bot)
|
||||
cfi_bot_tz = ChatFullInfo.de_json(json_dict, tz_bot)
|
||||
|
||||
# comparing utcoffsets because comparing tzinfo objects is not reliable
|
||||
emoji_expire_offset = cfi_bot_tz.emoji_status_expiration_date.utcoffset()
|
||||
emoji_expire_offset_tz = tz_bot.defaults.tzinfo.utcoffset(
|
||||
cfi_bot_tz.emoji_status_expiration_date.replace(tzinfo=None)
|
||||
)
|
||||
|
||||
assert cfi_bot.emoji_status_expiration_date.tzinfo == UTC
|
||||
assert cfi_bot_raw.emoji_status_expiration_date.tzinfo == UTC
|
||||
assert emoji_expire_offset_tz == emoji_expire_offset
|
||||
|
||||
def test_to_dict(self, chat_full_info):
|
||||
cfi = chat_full_info
|
||||
cfi_dict = cfi.to_dict()
|
||||
|
||||
assert isinstance(cfi_dict, dict)
|
||||
assert cfi_dict["id"] == cfi.id
|
||||
assert cfi_dict["title"] == cfi.title
|
||||
assert cfi_dict["type"] == cfi.type
|
||||
assert cfi_dict["username"] == cfi.username
|
||||
assert cfi_dict["permissions"] == cfi.permissions.to_dict()
|
||||
assert cfi_dict["slow_mode_delay"] == cfi.slow_mode_delay
|
||||
assert cfi_dict["bio"] == cfi.bio
|
||||
assert cfi_dict["business_intro"] == cfi.business_intro.to_dict()
|
||||
assert cfi_dict["business_location"] == cfi.business_location.to_dict()
|
||||
assert cfi_dict["business_opening_hours"] == cfi.business_opening_hours.to_dict()
|
||||
assert cfi_dict["has_private_forwards"] == cfi.has_private_forwards
|
||||
assert cfi_dict["has_protected_content"] == cfi.has_protected_content
|
||||
assert cfi_dict["has_visible_history"] == cfi.has_visible_history
|
||||
assert cfi_dict["linked_chat_id"] == cfi.linked_chat_id
|
||||
assert cfi_dict["location"] == cfi.location.to_dict()
|
||||
assert cfi_dict["join_to_send_messages"] == cfi.join_to_send_messages
|
||||
assert cfi_dict["join_by_request"] == cfi.join_by_request
|
||||
assert (
|
||||
cfi_dict["has_restricted_voice_and_video_messages"]
|
||||
== cfi.has_restricted_voice_and_video_messages
|
||||
)
|
||||
assert cfi_dict["is_forum"] == cfi.is_forum
|
||||
assert cfi_dict["active_usernames"] == list(cfi.active_usernames)
|
||||
assert cfi_dict["emoji_status_custom_emoji_id"] == cfi.emoji_status_custom_emoji_id
|
||||
assert cfi_dict["emoji_status_expiration_date"] == to_timestamp(
|
||||
cfi.emoji_status_expiration_date
|
||||
)
|
||||
assert cfi_dict["has_aggressive_anti_spam_enabled"] == cfi.has_aggressive_anti_spam_enabled
|
||||
assert cfi_dict["has_hidden_members"] == cfi.has_hidden_members
|
||||
assert cfi_dict["available_reactions"] == [
|
||||
reaction.to_dict() for reaction in cfi.available_reactions
|
||||
]
|
||||
assert cfi_dict["accent_color_id"] == cfi.accent_color_id
|
||||
assert cfi_dict["background_custom_emoji_id"] == cfi.background_custom_emoji_id
|
||||
assert cfi_dict["profile_accent_color_id"] == cfi.profile_accent_color_id
|
||||
assert (
|
||||
cfi_dict["profile_background_custom_emoji_id"]
|
||||
== cfi.profile_background_custom_emoji_id
|
||||
)
|
||||
assert cfi_dict["custom_emoji_sticker_set_name"] == cfi.custom_emoji_sticker_set_name
|
||||
assert cfi_dict["unrestrict_boost_count"] == cfi.unrestrict_boost_count
|
||||
assert cfi_dict["birthdate"] == cfi.birthdate.to_dict()
|
||||
assert cfi_dict["personal_chat"] == cfi.personal_chat.to_dict()
|
||||
assert cfi_dict["first_name"] == cfi.first_name
|
||||
assert cfi_dict["last_name"] == cfi.last_name
|
||||
|
||||
assert cfi_dict["max_reaction_count"] == cfi.max_reaction_count
|
||||
|
||||
def test_attr_access_no_warning(self, chat_full_info):
|
||||
cfi = chat_full_info
|
||||
for depr_attr in _deprecated_attrs:
|
||||
with warnings.catch_warnings(): # No warning should be raised
|
||||
warnings.simplefilter("error")
|
||||
getattr(cfi, depr_attr)
|
||||
|
||||
def test_cfi_creation_no_warning(self, chat_full_info):
|
||||
cfi = chat_full_info
|
||||
with warnings.catch_warnings():
|
||||
dict = cfi.to_dict()
|
||||
ChatFullInfo(**dict)
|
||||
def test_always_tuples_attributes(self):
|
||||
cfi = ChatFullInfo(
|
||||
id=123,
|
||||
type=Chat.PRIVATE,
|
||||
accent_color_id=1,
|
||||
max_reaction_count=2,
|
||||
)
|
||||
assert isinstance(cfi.active_usernames, tuple)
|
||||
assert cfi.active_usernames == ()
|
||||
|
|
|
@ -173,10 +173,9 @@ class TestConstantsWithoutRequest:
|
|||
"is_accessible",
|
||||
"quote",
|
||||
"external_reply",
|
||||
# attribute is deprecated, no need to add it to MessageType
|
||||
"user_shared",
|
||||
"via_bot",
|
||||
"is_from_offline",
|
||||
"show_caption_above_media",
|
||||
}
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
|
@ -273,6 +273,8 @@ def message(bot):
|
|||
{"sender_business_bot": User(1, "BusinessBot", True)},
|
||||
{"business_connection_id": "123456789"},
|
||||
{"chat_background_set": ChatBackground(type=BackgroundTypeChatTheme("ice"))},
|
||||
{"effect_id": "123456789"},
|
||||
{"show_caption_above_media": True},
|
||||
],
|
||||
ids=[
|
||||
"reply",
|
||||
|
@ -342,6 +344,8 @@ def message(bot):
|
|||
"business_connection_id",
|
||||
"is_from_offline",
|
||||
"chat_background_set",
|
||||
"effect_id",
|
||||
"show_caption_above_media",
|
||||
],
|
||||
)
|
||||
def message_params(bot, request):
|
||||
|
@ -399,11 +403,12 @@ class TestMessageBase:
|
|||
{"length": 2, "offset": 150, "type": "custom_emoji", "custom_emoji_id": "1"},
|
||||
{"length": 34, "offset": 154, "type": "blockquote"},
|
||||
{"length": 6, "offset": 181, "type": "bold"},
|
||||
{"length": 33, "offset": 190, "type": "expandable_blockquote"},
|
||||
]
|
||||
test_text_v2 = (
|
||||
r"Test for <bold, ita_lic, \`code, links, text-mention and `\pre. "
|
||||
"http://google.com and bold nested in strk>trgh nested in italic. Python pre. Spoiled. "
|
||||
"👍.\nMultiline\nblock quote\nwith nested."
|
||||
"👍.\nMultiline\nblock quote\nwith nested.\n\nMultiline\nexpandable\nblock quote."
|
||||
)
|
||||
test_message = Message(
|
||||
message_id=1,
|
||||
|
@ -728,7 +733,8 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
'<pre><code class="python">Python pre</code></pre>. '
|
||||
'<span class="tg-spoiler">Spoiled</span>. '
|
||||
'<tg-emoji emoji-id="1">👍</tg-emoji>.\n'
|
||||
"<blockquote>Multiline\nblock quote\nwith <b>nested</b>.</blockquote>"
|
||||
"<blockquote>Multiline\nblock quote\nwith <b>nested</b>.</blockquote>\n\n"
|
||||
"<blockquote expandable>Multiline\nexpandable\nblock quote.</blockquote>"
|
||||
)
|
||||
text_html = self.test_message_v2.text_html
|
||||
assert text_html == test_html_string
|
||||
|
@ -749,7 +755,8 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
'<pre><code class="python">Python pre</code></pre>. '
|
||||
'<span class="tg-spoiler">Spoiled</span>. '
|
||||
'<tg-emoji emoji-id="1">👍</tg-emoji>.\n'
|
||||
"<blockquote>Multiline\nblock quote\nwith <b>nested</b>.</blockquote>"
|
||||
"<blockquote>Multiline\nblock quote\nwith <b>nested</b>.</blockquote>\n\n"
|
||||
"<blockquote expandable>Multiline\nexpandable\nblock quote.</blockquote>"
|
||||
)
|
||||
text_html = self.test_message_v2.text_html_urled
|
||||
assert text_html == test_html_string
|
||||
|
@ -774,6 +781,9 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
">Multiline\n"
|
||||
">block quote\n"
|
||||
r">with *nested*\."
|
||||
"\n\n>Multiline\n"
|
||||
">expandable\n"
|
||||
r">block quote\.||"
|
||||
)
|
||||
text_markdown = self.test_message_v2.text_markdown_v2
|
||||
assert text_markdown == test_md_string
|
||||
|
@ -830,6 +840,9 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
">Multiline\n"
|
||||
">block quote\n"
|
||||
r">with *nested*\."
|
||||
"\n\n>Multiline\n"
|
||||
">expandable\n"
|
||||
r">block quote\.||"
|
||||
)
|
||||
text_markdown = self.test_message_v2.text_markdown_v2_urled
|
||||
assert text_markdown == test_md_string
|
||||
|
@ -946,7 +959,8 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
'<pre><code class="python">Python pre</code></pre>. '
|
||||
'<span class="tg-spoiler">Spoiled</span>. '
|
||||
'<tg-emoji emoji-id="1">👍</tg-emoji>.\n'
|
||||
"<blockquote>Multiline\nblock quote\nwith <b>nested</b>.</blockquote>"
|
||||
"<blockquote>Multiline\nblock quote\nwith <b>nested</b>.</blockquote>\n\n"
|
||||
"<blockquote expandable>Multiline\nexpandable\nblock quote.</blockquote>"
|
||||
)
|
||||
caption_html = self.test_message_v2.caption_html
|
||||
assert caption_html == test_html_string
|
||||
|
@ -967,7 +981,8 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
'<pre><code class="python">Python pre</code></pre>. '
|
||||
'<span class="tg-spoiler">Spoiled</span>. '
|
||||
'<tg-emoji emoji-id="1">👍</tg-emoji>.\n'
|
||||
"<blockquote>Multiline\nblock quote\nwith <b>nested</b>.</blockquote>"
|
||||
"<blockquote>Multiline\nblock quote\nwith <b>nested</b>.</blockquote>\n\n"
|
||||
"<blockquote expandable>Multiline\nexpandable\nblock quote.</blockquote>"
|
||||
)
|
||||
caption_html = self.test_message_v2.caption_html_urled
|
||||
assert caption_html == test_html_string
|
||||
|
@ -992,6 +1007,9 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
">Multiline\n"
|
||||
">block quote\n"
|
||||
r">with *nested*\."
|
||||
"\n\n>Multiline\n"
|
||||
">expandable\n"
|
||||
r">block quote\.||"
|
||||
)
|
||||
caption_markdown = self.test_message_v2.caption_markdown_v2
|
||||
assert caption_markdown == test_md_string
|
||||
|
@ -1023,6 +1041,9 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
">Multiline\n"
|
||||
">block quote\n"
|
||||
r">with *nested*\."
|
||||
"\n\n>Multiline\n"
|
||||
">expandable\n"
|
||||
r">block quote\.||"
|
||||
)
|
||||
caption_markdown = self.test_message_v2.caption_markdown_v2_urled
|
||||
assert caption_markdown == test_md_string
|
||||
|
@ -1484,6 +1505,9 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
">Multiline\n"
|
||||
">block quote\n"
|
||||
r">with *nested*\."
|
||||
"\n\n>Multiline\n"
|
||||
">expandable\n"
|
||||
r">block quote\.||"
|
||||
)
|
||||
|
||||
async def make_assertion(*_, **kwargs):
|
||||
|
@ -1534,7 +1558,8 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
'<pre><code class="python">Python pre</code></pre>. '
|
||||
'<span class="tg-spoiler">Spoiled</span>. '
|
||||
'<tg-emoji emoji-id="1">👍</tg-emoji>.\n'
|
||||
"<blockquote>Multiline\nblock quote\nwith <b>nested</b>.</blockquote>"
|
||||
"<blockquote>Multiline\nblock quote\nwith <b>nested</b>.</blockquote>\n\n"
|
||||
"<blockquote expandable>Multiline\nexpandable\nblock quote.</blockquote>"
|
||||
)
|
||||
|
||||
async def make_assertion(*_, **kwargs):
|
||||
|
@ -2599,7 +2624,9 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
async def test_default_do_quote(
|
||||
self, bot, message, default_quote, chat_type, expected, monkeypatch
|
||||
):
|
||||
message.set_bot(PytestExtBot(token=bot.token, defaults=Defaults(do_quote=default_quote)))
|
||||
original_bot = message.get_bot()
|
||||
temp_bot = PytestExtBot(token=bot.token, defaults=Defaults(do_quote=default_quote))
|
||||
message.set_bot(temp_bot)
|
||||
|
||||
async def make_assertion(*_, **kwargs):
|
||||
reply_parameters = kwargs.get("reply_parameters") or ReplyParameters(message_id=False)
|
||||
|
@ -2612,7 +2639,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.chat.type = chat_type
|
||||
assert await message.reply_text("test")
|
||||
finally:
|
||||
message.get_bot()._defaults = None
|
||||
message.set_bot(original_bot)
|
||||
|
||||
async def test_edit_forum_topic(self, monkeypatch, message):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
|
|
|
@ -35,9 +35,4 @@ def _change_test_dir(request, monkeypatch):
|
|||
|
||||
@skip_disabled
|
||||
def test_build():
|
||||
assert os.system("python setup.py bdist_dumb") == 0 # pragma: no cover
|
||||
|
||||
|
||||
@skip_disabled
|
||||
def test_build_raw():
|
||||
assert os.system("python setup_raw.py bdist_dumb") == 0 # pragma: no cover
|
||||
assert os.system("python -m build") == 0 # pragma: no cover
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
|
||||
from telegram import Animation, Audio, Document, PhotoSize, Sticker, Video, VideoNote, Voice
|
||||
from telegram._chat import _deprecated_attrs
|
||||
from tests.test_official.helpers import _get_params_base
|
||||
|
||||
IGNORED_OBJECTS = ("ResponseParameters",)
|
||||
|
@ -174,7 +173,7 @@ def ignored_param_requirements(object_name: str) -> set[str]:
|
|||
|
||||
# Arguments that are optional arguments for now for backwards compatibility
|
||||
BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = {
|
||||
"Chat": set(_deprecated_attrs), # removed by bot api 7.3
|
||||
"send_invoice|create_invoice_link|InputInvoiceMessageContent": {"provider_token"}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -342,10 +342,14 @@ class TestTelegramObject:
|
|||
chat = (await pp.get_chat_data())[1]
|
||||
assert chat.id == 1
|
||||
assert chat.type == Chat.PRIVATE
|
||||
assert chat.api_kwargs == {
|
||||
api_kwargs_expected = {
|
||||
"all_members_are_administrators": True,
|
||||
"something": "Manually inserted",
|
||||
}
|
||||
# There are older attrs in Chat's api_kwargs which are present but we don't care about them
|
||||
for k, v in api_kwargs_expected.items():
|
||||
assert chat.api_kwargs[k] == v
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
# removed attribute should not be available as attribute, only though api_kwargs
|
||||
chat.all_members_are_administrators
|
||||
|
|
|
@ -439,8 +439,8 @@ class TestUserWithoutRequest(TestUserBase):
|
|||
return from_chat_id and message_id and user_id
|
||||
|
||||
assert check_shortcut_signature(User.send_copy, Bot.copy_message, ["chat_id"], [])
|
||||
assert await check_shortcut_call(user.copy_message, user.get_bot(), "copy_message")
|
||||
assert await check_defaults_handling(user.copy_message, user.get_bot())
|
||||
assert await check_shortcut_call(user.send_copy, user.get_bot(), "copy_message")
|
||||
assert await check_defaults_handling(user.send_copy, user.get_bot())
|
||||
|
||||
monkeypatch.setattr(user.get_bot(), "copy_message", make_assertion)
|
||||
assert await user.send_copy(from_chat_id="from_chat_id", message_id="message_id")
|
||||
|
@ -700,3 +700,18 @@ class TestUserWithoutRequest(TestUserBase):
|
|||
|
||||
monkeypatch.setattr(user.get_bot(), "forward_messages", make_assertion)
|
||||
assert await user.forward_messages_to(chat_id="test_forwards", message_ids=(42, 43))
|
||||
|
||||
async def test_instance_method_refund_star_payment(self, monkeypatch, user):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["user_id"] == user.id and kwargs["telegram_payment_charge_id"] == 42
|
||||
|
||||
assert check_shortcut_signature(
|
||||
user.refund_star_payment, Bot.refund_star_payment, ["user_id"], []
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
user.refund_star_payment, user.get_bot(), "refund_star_payment"
|
||||
)
|
||||
assert await check_defaults_handling(user.refund_star_payment, user.get_bot())
|
||||
|
||||
monkeypatch.setattr(user.get_bot(), "refund_star_payment", make_assertion)
|
||||
assert await user.refund_star_payment(telegram_payment_charge_id=42)
|
||||
|
|
Loading…
Reference in a new issue