mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-21 16:45:17 +00:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a8f1164b0c | |||
| da11561f87 | |||
| 354a8e0854 | |||
| bc68488c14 | |||
| 19d7939355 | |||
| 3495ce3aeb | |||
| dd9af64a5c | |||
| da3bc6974a | |||
| b1fc0596b9 | |||
| 6d2334c88b | |||
| a0c81ec3d4 | |||
| c8d9898eaa | |||
| 616b0b55ef | |||
| c71612ffae | |||
| 4143d99f56 | |||
| cbe808e471 | |||
| 300ec920a1 | |||
| 075f517458 | |||
| c82a0808d1 | |||
| ea7e5a69aa | |||
| f67e8c0804 | |||
| af130ef5e7 | |||
| 9ef8826f33 | |||
| 61b70efb4c | |||
| 63977ea353 | |||
| ae57d3b7c3 | |||
| 8d76087bed | |||
| 0e90deafb5 | |||
| 39d45124df | |||
| 895403a0b5 | |||
| 8cb177cb2c | |||
| eaf802e07d | |||
| 1ef242a17e | |||
| 7adb4fa2db | |||
| 5c5ee598a2 | |||
| a4ae6f2097 | |||
| fc5a56c15b | |||
| 74112bfd06 | |||
| ab90cd7359 | |||
| 5b0f1697f1 | |||
| 9c7298c17a | |||
| 39abf838fa | |||
| 04b44f4595 | |||
| a0decdac28 | |||
| f77f4b0cf7 |
@@ -17,3 +17,4 @@ enabled = true
|
||||
runtime_version = "3.x.x"
|
||||
max_line_length = 99
|
||||
skip_doc_coverage = ["module", "magic", "init", "nonpublic"]
|
||||
cyclomatic_complexity_threshold = "high"
|
||||
|
||||
@@ -16,9 +16,9 @@ jobs:
|
||||
|
||||
- name: Fetch Dependabot metadata
|
||||
id: dependabot-metadata
|
||||
uses: dependabot/fetch-metadata@v1.6.1
|
||||
uses: dependabot/fetch-metadata@v1.6.0
|
||||
|
||||
- uses: actions/checkout@v3.5.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
|
||||
@@ -35,4 +35,4 @@ jobs:
|
||||
with:
|
||||
message: 'Update version number in other files'
|
||||
committer_name: GitHub Actions
|
||||
committer_email: 41898282+github-actions[bot]@users.noreply.github.com
|
||||
committer_email: 41898282+github-actions[bot]@users.noreply.github.com
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
os: [ubuntu-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
os: [ubuntu-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
pull-requests: write # for srvaroa/labeler to add labels in PR
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: srvaroa/labeler@v1.6.1
|
||||
- uses: srvaroa/labeler@v1.7.0
|
||||
# Config file at .github/labeler.yml
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
name: Bot API Tests
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
schedule:
|
||||
# Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions
|
||||
- cron: '7 3 * * 1,5'
|
||||
|
||||
jobs:
|
||||
check-conformity:
|
||||
name: check-conformity
|
||||
runs-on: ${{matrix.os}}
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.11]
|
||||
os: [ubuntu-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- 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
|
||||
- name: Compare to official api
|
||||
run: |
|
||||
pytest -v tests/test_official.py --junit-xml=.test_report_official.xml
|
||||
exit $?
|
||||
env:
|
||||
TEST_OFFICIAL: "true"
|
||||
shell: bash --noprofile --norc {0}
|
||||
|
||||
- name: Test Summary
|
||||
id: test_summary
|
||||
uses: test-summary/action@v2.1
|
||||
if: always() # always run, even if tests fail
|
||||
with:
|
||||
paths: .test_report_official.xml
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
name: test-type-completeness
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- run: git fetch --depth=1 # https://github.com/actions/checkout/issues/329#issuecomment-674881489
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
|
||||
@@ -16,11 +16,11 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12.0-rc.1']
|
||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
@@ -92,38 +92,3 @@ jobs:
|
||||
env_vars: OS,PYTHON
|
||||
name: ${{ matrix.os }}-${{ matrix.python-version }}
|
||||
fail_ci_if_error: true
|
||||
|
||||
test_official:
|
||||
name: test-official
|
||||
runs-on: ${{matrix.os}}
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.11]
|
||||
os: [ubuntu-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- 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
|
||||
- name: Compare to official api
|
||||
run: |
|
||||
pytest -v tests/test_official.py --junit-xml=.test_report_official.xml
|
||||
exit $?
|
||||
env:
|
||||
TEST_OFFICIAL: "true"
|
||||
shell: bash --noprofile --norc {0}
|
||||
|
||||
- name: Test Summary
|
||||
id: test_summary
|
||||
uses: test-summary/action@v2.1
|
||||
if: always() # always run, even if tests fail
|
||||
with:
|
||||
paths: .test_report_official.xml
|
||||
+16
-16
@@ -6,7 +6,7 @@ ci:
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.7.0
|
||||
rev: 23.10.1
|
||||
hooks:
|
||||
- id: black
|
||||
args:
|
||||
@@ -17,7 +17,7 @@ repos:
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/PyCQA/pylint
|
||||
rev: v3.0.0a6
|
||||
rev: v3.0.1
|
||||
hooks:
|
||||
- id: pylint
|
||||
files: ^(telegram|examples)/.*\.py$
|
||||
@@ -28,14 +28,14 @@ repos:
|
||||
- --jobs=0
|
||||
|
||||
additional_dependencies:
|
||||
- httpx~=0.24.1
|
||||
- tornado~=6.2
|
||||
- httpx~=0.25.2
|
||||
- tornado~=6.3.3
|
||||
- APScheduler~=3.10.4
|
||||
- cachetools~=5.3.1
|
||||
- cachetools~=5.3.2
|
||||
- aiolimiter~=1.1.0
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.4.1
|
||||
rev: v1.6.1
|
||||
hooks:
|
||||
- id: mypy
|
||||
name: mypy-ptb
|
||||
@@ -44,10 +44,10 @@ repos:
|
||||
- types-pytz
|
||||
- types-cryptography
|
||||
- types-cachetools
|
||||
- httpx~=0.24.1
|
||||
- tornado~=6.2
|
||||
- httpx~=0.25.2
|
||||
- tornado~=6.3.3
|
||||
- APScheduler~=3.10.4
|
||||
- cachetools~=5.3.1
|
||||
- cachetools~=5.3.2
|
||||
- aiolimiter~=1.1.0
|
||||
- . # this basically does `pip install -e .`
|
||||
- id: mypy
|
||||
@@ -57,12 +57,12 @@ repos:
|
||||
- --no-strict-optional
|
||||
- --follow-imports=silent
|
||||
additional_dependencies:
|
||||
- tornado~=6.2
|
||||
- tornado~=6.3.3
|
||||
- APScheduler~=3.10.4
|
||||
- cachetools~=5.3.1
|
||||
- cachetools~=5.3.2
|
||||
- . # this basically does `pip install -e .`
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.10.1
|
||||
rev: v3.15.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
files: ^(telegram|examples|tests|docs)/.*\.py$
|
||||
@@ -77,14 +77,14 @@ repos:
|
||||
- --diff
|
||||
- --check
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: 'v0.0.281'
|
||||
rev: 'v0.1.5'
|
||||
hooks:
|
||||
- id: ruff
|
||||
name: ruff
|
||||
files: ^(telegram|examples|tests)/.*\.py$
|
||||
additional_dependencies:
|
||||
- httpx~=0.24.1
|
||||
- tornado~=6.2
|
||||
- httpx~=0.25.2
|
||||
- tornado~=6.3.3
|
||||
- APScheduler~=3.10.4
|
||||
- cachetools~=5.3.1
|
||||
- cachetools~=5.3.2
|
||||
- aiolimiter~=1.1.0
|
||||
|
||||
+99
@@ -4,6 +4,105 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
Version 20.6
|
||||
============
|
||||
|
||||
*Released 2023-11-27*
|
||||
|
||||
This is the technical changelog for version 20.6. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`__.
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
- Add ``JobQueue.scheduler_configuration`` and Corresponding Warnings (:pr:`3913` closes :issue:`3837`)
|
||||
- Add Parameter ``socket_options`` to ``HTTPXRequest`` (:pr:`3935` closes :issue:`2965`)
|
||||
- Add ``ApplicationBuilder.(get_updates_)socket_options`` (:pr:`3943`)
|
||||
- Improve ``write_timeout`` Handling for Media Methods (:pr:`3952`)
|
||||
- Add ``filters.Mention`` (:pr:`3941` closes :issue:`3799`)
|
||||
- Rename ``proxy_url`` to ``proxy`` and Allow ``httpx.{Proxy, URL}`` as Input (:pr:`3939` closes :issue:`3844`)
|
||||
|
||||
Bug Fixes & Changes
|
||||
-------------------
|
||||
|
||||
- Adjust ``read_timeout`` Behavior for ``Bot.get_updates`` (:pr:`3963` closes :issue:`3893`)
|
||||
- Improve ``BaseHandler.__repr__`` for Callbacks without ``__qualname__`` (:pr:`3934`)
|
||||
- Fix Persistency Issue with Ended Non-Blocking Conversations (:pr:`3962`)
|
||||
- Improve Type Hinting for Arguments with Default Values in ``Bot`` (:pr:`3942`)
|
||||
|
||||
Documentation Improvements
|
||||
--------------------------
|
||||
|
||||
- Add Documentation for ``__aenter__`` and ``__aexit__`` Methods (:pr:`3907` closes :issue:`3886`)
|
||||
- Improve Insertion of Kwargs into ``Bot`` Methods (:pr:`3965`)
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Adjust Tests to New Error Messages (:pr:`3970`)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- Bump ``pytest-xdist`` from 3.3.1 to 3.4.0 (:pr:`3975`)
|
||||
- ``pre-commit`` autoupdate (:pr:`3967`)
|
||||
- Update ``httpx`` requirement from ~=0.25.1 to ~=0.25.2 (:pr:`3983`)
|
||||
- Bump ``pytest-xdist`` from 3.4.0 to 3.5.0 (:pr:`3982`)
|
||||
- Update ``httpx`` requirement from ~=0.25.0 to ~=0.25.1 (:pr:`3961`)
|
||||
- Bump ``srvaroa/labeler`` from 1.6.1 to 1.7.0 (:pr:`3958`)
|
||||
- Update ``cachetools`` requirement from ~=5.3.1 to ~=5.3.2 (:pr:`3954`)
|
||||
- Bump ``pytest`` from 7.4.2 to 7.4.3 (:pr:`3953`)
|
||||
|
||||
|
||||
Version 20.6
|
||||
============
|
||||
|
||||
*Released 2023-10-03*
|
||||
|
||||
This is the technical changelog for version 20.6. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`__.
|
||||
|
||||
Major Changes
|
||||
-------------
|
||||
|
||||
- Drop Backward Compatibility Layer Introduced in :pr:`3853` (API 6.8) (:pr:`3873`)
|
||||
- Full Support for Bot API 6.9 (:pr:`3898`)
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
- Add Rich Equality Comparison to ``WriteAccessAllowed`` (:pr:`3911` closes :issue:`3909`)
|
||||
- Add ``__repr__`` Methods Added in :pr:`3826` closes :issue:`3770` to Sphinx Documentation (:pr:`3901` closes :issue:`3889`)
|
||||
- Add String Representation for Selected Classes (:pr:`3826` closes :issue:`3770`)
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- Add Support Python 3.12 (:pr:`3915`)
|
||||
- Documentation Improvements (:pr:`3910`)
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Verify Type Hints for Bot Method & Telegram Class Parameters (:pr:`3868`)
|
||||
- Move Bot API Tests to Separate Workflow File (:pr:`3912`)
|
||||
- Fix Failing ``file_size`` Tests (:pr:`3906`)
|
||||
- Set Threshold for DeepSource’s PY-R1000 to High (:pr:`3888`)
|
||||
- One-Time Code Formatting Improvement via ``--preview`` Flag of ``black`` (:pr:`3882`)
|
||||
- Move Dunder Methods to the Top of Class Bodies (:pr:`3883`)
|
||||
- Remove Superfluous ``Defaults.__ne__`` (:pr:`3884`)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- ``pre-commit`` autoupdate (:pr:`3876`)
|
||||
- Update ``pre-commit`` Dependencies (:pr:`3916`)
|
||||
- Bump ``actions/checkout`` from 3 to 4 (:pr:`3914`)
|
||||
- Update ``httpx`` requirement from ~=0.24.1 to ~=0.25.0 (:pr:`3891`)
|
||||
- Bump ``furo`` from 2023.8.19 to 2023.9.10 (:pr:`3890`)
|
||||
- Bump ``sphinx`` from 7.2.5 to 7.2.6 (:pr:`3892`)
|
||||
- Update ``tornado`` requirement from ~=6.2 to ~=6.3.3 (:pr:`3675`)
|
||||
- Bump ``pytest`` from 7.4.0 to 7.4.2 (:pr:`3881`)
|
||||
|
||||
|
||||
Version 20.5
|
||||
============
|
||||
*Released 2023-09-03*
|
||||
|
||||
+5
-5
@@ -14,7 +14,7 @@
|
||||
:target: https://pypi.org/project/python-telegram-bot/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.8-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.9-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
@@ -93,7 +93,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
|
||||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **6.8** are supported.
|
||||
All types and methods of the Telegram Bot API **6.9** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
@@ -135,7 +135,7 @@ As these features are *optional*, the corresponding 3rd party dependencies are n
|
||||
Instead, they are listed as optional dependencies.
|
||||
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
|
||||
|
||||
The only required dependency is `httpx ~= 0.24.1 <https://www.python-httpx.org>`_ for
|
||||
The only required dependency is `httpx ~= 0.25.2 <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.
|
||||
@@ -152,8 +152,8 @@ PTB can be installed with optional dependencies:
|
||||
* ``pip install "python-telegram-bot[socks]"`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
|
||||
* ``pip install "python-telegram-bot[http2]"`` installs `httpx[http2] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to use HTTP/2.
|
||||
* ``pip install "python-telegram-bot[rate-limiter]"`` installs `aiolimiter~=1.1.0 <https://aiolimiter.readthedocs.io/en/stable/>`_. Use this, if you want to use ``telegram.ext.AIORateLimiter``.
|
||||
* ``pip install "python-telegram-bot[webhooks]"`` installs the `tornado~=6.2 <https://www.tornadoweb.org/en/stable/>`_ library. Use this, if you want to use ``telegram.ext.Updater.start_webhook``/``telegram.ext.Application.run_webhook``.
|
||||
* ``pip install "python-telegram-bot[callback-data]"`` installs the `cachetools~=5.3.1 <https://cachetools.readthedocs.io/en/latest/>`_ library. Use this, if you want to use `arbitrary callback_data <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Arbitrary-callback_data>`_.
|
||||
* ``pip install "python-telegram-bot[webhooks]"`` installs the `tornado~=6.3.3 <https://www.tornadoweb.org/en/stable/>`_ library. Use this, if you want to use ``telegram.ext.Updater.start_webhook``/``telegram.ext.Application.run_webhook``.
|
||||
* ``pip install "python-telegram-bot[callback-data]"`` installs the `cachetools~=5.3.2 <https://cachetools.readthedocs.io/en/latest/>`_ library. Use this, if you want to use `arbitrary callback_data <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Arbitrary-callback_data>`_.
|
||||
* ``pip install "python-telegram-bot[job-queue]"`` installs the `APScheduler~=3.10.4 <https://apscheduler.readthedocs.io/en/3.x/>`_ library and enforces `pytz>=2018.6 <https://pypi.org/project/pytz/>`_, where ``pytz`` is a dependency of ``APScheduler``. Use this, if you want to use the ``telegram.ext.JobQueue``.
|
||||
|
||||
To install multiple optional dependencies, separate them by commas, e.g. ``pip install "python-telegram-bot[socks,webhooks]"``.
|
||||
|
||||
+3
-3
@@ -14,7 +14,7 @@
|
||||
:target: https://pypi.org/project/python-telegram-bot-raw/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.8-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.9-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
@@ -89,7 +89,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
|
||||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **6.8** are supported.
|
||||
All types and methods of the Telegram Bot API **6.9** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
@@ -136,7 +136,7 @@ As these features are *optional*, the corresponding 3rd party dependencies are n
|
||||
Instead, they are listed as optional dependencies.
|
||||
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
|
||||
|
||||
The only required dependency is `httpx ~= 0.24.1 <https://www.python-httpx.org>`_ for
|
||||
The only required dependency is `httpx ~= 0.25.2 <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.
|
||||
|
||||
@@ -194,7 +194,7 @@ class AdmonitionInserter:
|
||||
)
|
||||
except NotImplementedError as e:
|
||||
raise NotImplementedError(
|
||||
f"Error generating Sphinx 'Available in' admonition "
|
||||
"Error generating Sphinx 'Available in' admonition "
|
||||
f"(admonition_inserter.py). Class {name_of_class_in_attr} present in "
|
||||
f"attribute {target_attr} of class {name_of_inspected_class_in_docstr}"
|
||||
f" could not be resolved. {str(e)}"
|
||||
@@ -237,7 +237,7 @@ class AdmonitionInserter:
|
||||
)
|
||||
except NotImplementedError as e:
|
||||
raise NotImplementedError(
|
||||
f"Error generating Sphinx 'Available in' admonition "
|
||||
"Error generating Sphinx 'Available in' admonition "
|
||||
f"(admonition_inserter.py). Class {name_of_class_in_prop} present in "
|
||||
f"property {prop_name} of class {name_of_inspected_class_in_docstr}"
|
||||
f" could not be resolved. {str(e)}"
|
||||
@@ -269,7 +269,7 @@ class AdmonitionInserter:
|
||||
)
|
||||
except NotImplementedError as e:
|
||||
raise NotImplementedError(
|
||||
f"Error generating Sphinx 'Returned in' admonition "
|
||||
"Error generating Sphinx 'Returned in' admonition "
|
||||
f"(admonition_inserter.py). {cls}, method {method_name}. "
|
||||
f"Couldn't resolve type hint in return annotation {ret_annot}. {str(e)}"
|
||||
)
|
||||
@@ -342,7 +342,7 @@ class AdmonitionInserter:
|
||||
)
|
||||
except NotImplementedError as e:
|
||||
raise NotImplementedError(
|
||||
f"Error generating Sphinx 'Use in' admonition "
|
||||
"Error generating Sphinx 'Use in' admonition "
|
||||
f"(admonition_inserter.py). {cls}, method {method_name}, parameter "
|
||||
f"{param}: Couldn't resolve type hint {param.annotation}. {str(e)}"
|
||||
)
|
||||
|
||||
@@ -18,51 +18,80 @@
|
||||
import inspect
|
||||
|
||||
keyword_args = [
|
||||
":keyword _sphinx_paramlinks_telegram.Bot.{method}.read_timeout: Value to pass to "
|
||||
":paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to {read_timeout}.",
|
||||
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.read_timeout: {read_timeout_type}, optional",
|
||||
":keyword _sphinx_paramlinks_telegram.Bot.{method}.write_timeout: Value to pass to "
|
||||
":paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to {write_timeout}.",
|
||||
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.write_timeout: :obj:`float` | :obj:`None`, "
|
||||
"optional",
|
||||
":keyword _sphinx_paramlinks_telegram.Bot.{method}.connect_timeout: Value to pass to "
|
||||
":paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to "
|
||||
":attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.",
|
||||
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.connect_timeout: :obj:`float` | "
|
||||
":obj:`None`, optional",
|
||||
":keyword _sphinx_paramlinks_telegram.Bot.{method}.pool_timeout: Value to pass to "
|
||||
":paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to "
|
||||
":attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.",
|
||||
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.pool_timeout: :obj:`float` | :obj:`None`, "
|
||||
"optional",
|
||||
":keyword _sphinx_paramlinks_telegram.Bot.{method}.api_kwargs: Arbitrary keyword arguments "
|
||||
"to be passed to the Telegram API.",
|
||||
":kwtype _sphinx_paramlinks_telegram.Bot.{method}.api_kwargs: :obj:`dict`, optional",
|
||||
"Keyword Arguments:",
|
||||
(
|
||||
" read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to "
|
||||
" :paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to "
|
||||
" :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. "
|
||||
),
|
||||
(
|
||||
" write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to "
|
||||
" :paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to "
|
||||
" :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`."
|
||||
),
|
||||
(
|
||||
" connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to "
|
||||
" :paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to "
|
||||
" :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`."
|
||||
),
|
||||
(
|
||||
" pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to "
|
||||
" :paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to "
|
||||
" :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`."
|
||||
),
|
||||
(
|
||||
" api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments"
|
||||
" to be passed to the Telegram API."
|
||||
),
|
||||
"",
|
||||
]
|
||||
write_timeout_sub = [":attr:`~telegram.request.BaseRequest.DEFAULT_NONE`", "``20``"]
|
||||
read_timeout_sub = [
|
||||
":attr:`~telegram.request.BaseRequest.DEFAULT_NONE`",
|
||||
"``2``. :paramref:`timeout` will be added to this value",
|
||||
|
||||
media_write_timeout_deprecation_methods = [
|
||||
"send_photo",
|
||||
"send_audio",
|
||||
"send_document",
|
||||
"send_sticker",
|
||||
"send_video",
|
||||
"send_video_note",
|
||||
"send_animation",
|
||||
"send_voice",
|
||||
"send_media_group",
|
||||
"set_chat_photo",
|
||||
"upload_sticker_file",
|
||||
"add_sticker_to_set",
|
||||
"create_new_sticker_set",
|
||||
]
|
||||
media_write_timeout_deprecation = [
|
||||
" write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to "
|
||||
" :paramref:`telegram.request.BaseRequest.post.write_timeout`. By default, ``20`` "
|
||||
" seconds are used as write timeout."
|
||||
"",
|
||||
"",
|
||||
" .. deprecated:: 20.7",
|
||||
" In future versions, the default value will be changed to "
|
||||
" :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.",
|
||||
"",
|
||||
"",
|
||||
]
|
||||
get_updates_read_timeout_addition = [
|
||||
" :paramref:`timeout` will be added to this value.",
|
||||
"",
|
||||
"",
|
||||
" .. versionchanged:: 20.7",
|
||||
" Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE` instead of ",
|
||||
" ``2``.",
|
||||
]
|
||||
read_timeout_type = [":obj:`float` | :obj:`None`", ":obj:`float`"]
|
||||
|
||||
|
||||
def find_insert_pos_for_kwargs(lines: list[str]) -> int:
|
||||
"""Finds the correct position to insert the keyword arguments and returns the index."""
|
||||
for idx, value in reversed(list(enumerate(lines))): # reversed since :returns: is at the end
|
||||
if value.startswith(":returns:"):
|
||||
if value.startswith("Returns"):
|
||||
return idx
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def is_write_timeout_20(obj: object) -> int:
|
||||
"""inspects the default value of write_timeout parameter of the bot method."""
|
||||
sig = inspect.signature(obj)
|
||||
return 1 if (sig.parameters["write_timeout"].default == 20) else 0
|
||||
|
||||
|
||||
def check_timeout_and_api_kwargs_presence(obj: object) -> int:
|
||||
"""Checks if the method has timeout and api_kwargs keyword only parameters."""
|
||||
sig = inspect.signature(obj)
|
||||
|
||||
+19
-15
@@ -29,11 +29,10 @@ from docs.auxil.admonition_inserter import AdmonitionInserter
|
||||
from docs.auxil.kwargs_insertion import (
|
||||
check_timeout_and_api_kwargs_presence,
|
||||
find_insert_pos_for_kwargs,
|
||||
is_write_timeout_20,
|
||||
get_updates_read_timeout_addition,
|
||||
keyword_args,
|
||||
read_timeout_sub,
|
||||
read_timeout_type,
|
||||
write_timeout_sub,
|
||||
media_write_timeout_deprecation,
|
||||
media_write_timeout_deprecation_methods,
|
||||
)
|
||||
from docs.auxil.link_code import LINE_NUMBERS
|
||||
|
||||
@@ -107,19 +106,24 @@ def autodoc_process_docstring(
|
||||
f"Couldn't find the correct position to insert the keyword args for {obj}."
|
||||
)
|
||||
|
||||
long_write_timeout = is_write_timeout_20(obj)
|
||||
get_updates_sub = 1 if (method_name == "get_updates") else 0
|
||||
get_updates: bool = method_name == "get_updates"
|
||||
# The below can be done in 1 line with itertools.chain, but this must be modified in-place
|
||||
insert_idx = insert_index
|
||||
for i in range(insert_index, insert_index + len(keyword_args)):
|
||||
lines.insert(
|
||||
i,
|
||||
keyword_args[i - insert_index].format(
|
||||
method=method_name,
|
||||
write_timeout=write_timeout_sub[long_write_timeout],
|
||||
read_timeout=read_timeout_sub[get_updates_sub],
|
||||
read_timeout_type=read_timeout_type[get_updates_sub],
|
||||
),
|
||||
)
|
||||
to_insert = keyword_args[i - insert_index]
|
||||
|
||||
if (
|
||||
"post.write_timeout`. Defaults to" in to_insert
|
||||
and method_name in media_write_timeout_deprecation_methods
|
||||
):
|
||||
effective_insert: list[str] = media_write_timeout_deprecation
|
||||
elif get_updates and to_insert.lstrip().startswith("read_timeout"):
|
||||
effective_insert = [to_insert] + get_updates_read_timeout_addition
|
||||
else:
|
||||
effective_insert = [to_insert]
|
||||
|
||||
lines[insert_idx:insert_idx] = effective_insert
|
||||
insert_idx += len(effective_insert)
|
||||
|
||||
ADMONITION_INSERTER.insert_admonitions(
|
||||
obj=typing.cast(collections.abc.Callable, obj),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
sphinx==7.2.5
|
||||
sphinx==7.2.6
|
||||
sphinx-pypi-upload
|
||||
furo==2023.8.19
|
||||
furo==2023.9.10
|
||||
git+https://github.com/harshil21/furo-sphinx-search@v0.2.0.1
|
||||
sphinx-paramlinks==0.6.0
|
||||
sphinxcontrib-mermaid==0.9.2
|
||||
|
||||
+72
-53
@@ -21,9 +21,9 @@ author = "Leandro Toledo"
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = "20.5" # telegram.__version__[:3]
|
||||
version = "20.7" # telegram.__version__[:3]
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = "20.5" # telegram.__version__
|
||||
release = "20.7" # telegram.__version__
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
needs_sphinx = "6.1.3"
|
||||
@@ -77,6 +77,12 @@ napoleon_use_admonition_for_examples = True
|
||||
# and we document the types anyway
|
||||
autodoc_typehints = "none"
|
||||
|
||||
# Show docstring for special members
|
||||
autodoc_default_options = {
|
||||
"special-members": True,
|
||||
"exclude-members": "__init__",
|
||||
}
|
||||
|
||||
# Fail on warnings & unresolved references etc
|
||||
nitpicky = True
|
||||
|
||||
@@ -96,7 +102,9 @@ linkcheck_ignore = [
|
||||
]
|
||||
linkcheck_allowed_redirects = {
|
||||
# Redirects to the default version are okay
|
||||
r"https://docs\.python-telegram-bot\.org/.*": r"https://docs\.python-telegram-bot\.org/en/[\w\d\.]+/.*",
|
||||
r"https://docs\.python-telegram-bot\.org/.*": (
|
||||
r"https://docs\.python-telegram-bot\.org/en/[\w\d\.]+/.*"
|
||||
),
|
||||
# pre-commit.ci always redirects to the latest run
|
||||
re.escape(
|
||||
"https://results.pre-commit.ci/latest/github/python-telegram-bot/python-telegram-bot/master"
|
||||
@@ -131,71 +139,79 @@ html_theme_options = {
|
||||
"admonition-title-font-size": "0.95rem",
|
||||
"admonition-font-size": "0.92rem",
|
||||
},
|
||||
"announcement": "PTB has undergone significant changes in v20. Please read the documentation "
|
||||
"carefully and also check out the transition guide in the "
|
||||
'<a href="https://github.com/python-telegram-bot/python-telegram-bot/wiki/'
|
||||
'Transition-guide-to-Version-20.0">wiki</a>.',
|
||||
"announcement": (
|
||||
"PTB has undergone significant changes in v20. Please read the documentation "
|
||||
"carefully and also check out the transition guide in the "
|
||||
'<a href="https://github.com/python-telegram-bot/python-telegram-bot/wiki/'
|
||||
'Transition-guide-to-Version-20.0">wiki</a>.'
|
||||
),
|
||||
"footer_icons": [
|
||||
{
|
||||
# Telegram channel logo
|
||||
"name": "Telegram Channel",
|
||||
"url": "https://t.me/pythontelegrambotchannel/",
|
||||
# Following svg is from https://react-icons.github.io/react-icons/search?q=telegram
|
||||
"html": '<svg stroke="currentColor" fill="currentColor" stroke-width="0" '
|
||||
'viewBox="0 0 16 16" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">'
|
||||
'<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8.287 5.906c-.778.324-2.334.994'
|
||||
"-4.666 2.01-.378.15-.577.298-.595.442-.03.243.275.339.69.47l.175.055c.408.133."
|
||||
"958.288 1.243.294.26.006.549-.1.868-.32 2.179-1.471 3.304-2.214 3.374-2.23.0"
|
||||
"5-.012.12-.026.166.016.047.041.042.12.037.141-.03.129-1.227 1.241-1.846 1.81"
|
||||
"7-.193.18-.33.307-.358.336a8.154 8.154 0 0 1-.188.186c-.38.366-.664.64.015 1.08"
|
||||
"8.327.216.589.393.85.571.284.194.568.387.936.629.093.06.183.125.27.187.331.23"
|
||||
"6.63.448.997.414.214-.02.435-.22.547-.82.265-1.417.786-4.486.906-5.751a1.426 "
|
||||
"1.426 0 0 0-.013-.315.337.337 0 0 0-.114-.217.526.526 0 0 0-.31-.093c-.3.005-.7"
|
||||
'63.166-2.984 1.09z"></path></svg>',
|
||||
"html": (
|
||||
'<svg stroke="currentColor" fill="currentColor" stroke-width="0" '
|
||||
'viewBox="0 0 16 16" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">'
|
||||
'<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8.287 5.906c-.778.324-2.334.994'
|
||||
"-4.666 2.01-.378.15-.577.298-.595.442-.03.243.275.339.69.47l.175.055c.408.133."
|
||||
"958.288 1.243.294.26.006.549-.1.868-.32 2.179-1.471 3.304-2.214 3.374-2.23.0"
|
||||
"5-.012.12-.026.166.016.047.041.042.12.037.141-.03.129-1.227 1.241-1.846 1.81"
|
||||
"7-.193.18-.33.307-.358.336a8.154 8.154 0 0 1-.188.186c-.38.366-.664.64.015 1.08"
|
||||
"8.327.216.589.393.85.571.284.194.568.387.936.629.093.06.183.125.27.187.331.23"
|
||||
"6.63.448.997.414.214-.02.435-.22.547-.82.265-1.417.786-4.486.906-5.751a1.426 "
|
||||
"1.426 0 0 0-.013-.315.337.337 0 0 0-.114-.217.526.526 0 0 0-.31-.093c-.3.005-.7"
|
||||
'63.166-2.984 1.09z"></path></svg>'
|
||||
),
|
||||
"class": "",
|
||||
},
|
||||
{ # Github logo
|
||||
"name": "GitHub",
|
||||
"url": "https://github.com/python-telegram-bot/python-telegram-bot/",
|
||||
"html": '<svg stroke="currentColor" fill="currentColor" stroke-width="0" '
|
||||
'viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 '
|
||||
"2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.4"
|
||||
"9-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23"
|
||||
".82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 "
|
||||
"0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.2"
|
||||
"7 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.5"
|
||||
"1.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 "
|
||||
'1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z">'
|
||||
"</path></svg>",
|
||||
"html": (
|
||||
'<svg stroke="currentColor" fill="currentColor" stroke-width="0" '
|
||||
'viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 '
|
||||
"2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.4"
|
||||
"9-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23"
|
||||
".82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 "
|
||||
"0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.2"
|
||||
"7 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.5"
|
||||
"1.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 "
|
||||
'1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z">'
|
||||
"</path></svg>"
|
||||
),
|
||||
"class": "",
|
||||
},
|
||||
{ # PTB website logo - globe
|
||||
"name": "python-telegram-bot website",
|
||||
"url": "https://python-telegram-bot.org/",
|
||||
"html": '<svg stroke="currentColor" fill="currentColor" stroke-width="0" '
|
||||
'viewBox="0 0 16 16" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">'
|
||||
'<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 '
|
||||
"1.855-.143.268-.276.56-.395.872.705.157 1.472.257 2.282.287V1.077zM4.249 3.53"
|
||||
"9c.142-.384.304-.744.481-1.078a6.7 6.7 0 0 1 .597-.933A7.01 7.01 0 0 0 3.051 "
|
||||
"3.05c.362.184.763.349 1.198.49zM3.509 7.5c.036-1.07.188-2.087.436-3.008a9.124 "
|
||||
"9.124 0 0 1-1.565-.667A6.964 6.964 0 0 0 1.018 7.5h2.49zm1.4-2.741a12.344 "
|
||||
"12.344 0 0 0-.4 2.741H7.5V5.091c-.91-.03-1.783-.145-2.591-.332zM8.5 5.09V7.5h"
|
||||
"2.99a12.342 12.342 0 0 0-.399-2.741c-.808.187-1.681.301-2.591.332zM4.51 8.5c.03"
|
||||
"5.987.176 1.914.399 2.741A13.612 13.612 0 0 1 7.5 10.91V8.5H4.51zm3.99 0v2.409"
|
||||
"c.91.03 1.783.145 2.591.332.223-.827.364-1.754.4-2.741H8.5zm-3.282 3.696c.12.31"
|
||||
"2.252.604.395.872.552 1.035 1.218 1.65 1.887 1.855V11.91c-.81.03-1.577.13-2.28"
|
||||
"2.287zm.11 2.276a6.696 6.696 0 0 1-.598-.933 8.853 8.853 0 0 1-.481-1.079 8.38 "
|
||||
"8.38 0 0 0-1.198.49 7.01 7.01 0 0 0 2.276 1.522zm-1.383-2.964A13.36 13.36 0 0 1"
|
||||
" 3.508 8.5h-2.49a6.963 6.963 0 0 0 1.362 3.675c.47-.258.995-.482 1.565-.667zm"
|
||||
"6.728 2.964a7.009 7.009 0 0 0 2.275-1.521 8.376 8.376 0 0 0-1.197-.49 8.853 "
|
||||
"8.853 0 0 1-.481 1.078 6.688 6.688 0 0 1-.597.933zM8.5 11.909v3.014c.67-.204 "
|
||||
"1.335-.82 1.887-1.855.143-.268.276-.56.395-.872A12.63 12.63 0 0 0 8.5 11.91zm"
|
||||
"3.555-.401c.57.185 1.095.409 1.565.667A6.963 6.963 0 0 0 14.982 8.5h-2.49a1"
|
||||
"3.36 13.36 0 0 1-.437 3.008zM14.982 7.5a6.963 6.963 0 0 0-1.362-3.675c-.47.25"
|
||||
"8-.995.482-1.565.667.248.92.4 1.938.437 3.008h2.49zM11.27 2.461c.177.334.339.6"
|
||||
"94.482 1.078a8.368 8.368 0 0 0 1.196-.49 7.01 7.01 0 0 0-2.275-1.52c.218.283.4"
|
||||
"18.597.597.932zm-.488 1.343a7.765 7.765 0 0 0-.395-.872C9.835 1.897 9.17 1.282 "
|
||||
'8.5 1.077V4.09c.81-.03 1.577-.13 2.282-.287z"></path></svg>',
|
||||
"html": (
|
||||
'<svg stroke="currentColor" fill="currentColor" stroke-width="0" '
|
||||
'viewBox="0 0 16 16" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">'
|
||||
'<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 '
|
||||
"1.855-.143.268-.276.56-.395.872.705.157 1.472.257 2.282.287V1.077zM4.249 3.53"
|
||||
"9c.142-.384.304-.744.481-1.078a6.7 6.7 0 0 1 .597-.933A7.01 7.01 0 0 0 3.051 "
|
||||
"3.05c.362.184.763.349 1.198.49zM3.509 7.5c.036-1.07.188-2.087.436-3.008a9.124 "
|
||||
"9.124 0 0 1-1.565-.667A6.964 6.964 0 0 0 1.018 7.5h2.49zm1.4-2.741a12.344 "
|
||||
"12.344 0 0 0-.4 2.741H7.5V5.091c-.91-.03-1.783-.145-2.591-.332zM8.5 5.09V7.5h"
|
||||
"2.99a12.342 12.342 0 0 0-.399-2.741c-.808.187-1.681.301-2.591.332zM4.51 8.5c.03"
|
||||
"5.987.176 1.914.399 2.741A13.612 13.612 0 0 1 7.5 10.91V8.5H4.51zm3.99 0v2.409"
|
||||
"c.91.03 1.783.145 2.591.332.223-.827.364-1.754.4-2.741H8.5zm-3.282 3.696c.12.31"
|
||||
"2.252.604.395.872.552 1.035 1.218 1.65 1.887 1.855V11.91c-.81.03-1.577.13-2.28"
|
||||
"2.287zm.11 2.276a6.696 6.696 0 0 1-.598-.933 8.853 8.853 0 0 1-.481-1.079 8.38 "
|
||||
"8.38 0 0 0-1.198.49 7.01 7.01 0 0 0 2.276 1.522zm-1.383-2.964A13.36 13.36 0 0 1"
|
||||
" 3.508 8.5h-2.49a6.963 6.963 0 0 0 1.362 3.675c.47-.258.995-.482 1.565-.667zm"
|
||||
"6.728 2.964a7.009 7.009 0 0 0 2.275-1.521 8.376 8.376 0 0 0-1.197-.49 8.853 "
|
||||
"8.853 0 0 1-.481 1.078 6.688 6.688 0 0 1-.597.933zM8.5 11.909v3.014c.67-.204 "
|
||||
"1.335-.82 1.887-1.855.143-.268.276-.56.395-.872A12.63 12.63 0 0 0 8.5 11.91zm"
|
||||
"3.555-.401c.57.185 1.095.409 1.565.667A6.963 6.963 0 0 0 14.982 8.5h-2.49a1"
|
||||
"3.36 13.36 0 0 1-.437 3.008zM14.982 7.5a6.963 6.963 0 0 0-1.362-3.675c-.47.25"
|
||||
"8-.995.482-1.565.667.248.92.4 1.938.437 3.008h2.49zM11.27 2.461c.177.334.339.6"
|
||||
"94.482 1.078a8.368 8.368 0 0 0 1.196-.49 7.01 7.01 0 0 0-2.275-1.52c.218.283.4"
|
||||
"18.597.597.932zm-.488 1.343a7.765 7.765 0 0 0-.395-.872C9.835 1.897 9.17 1.282 "
|
||||
'8.5 1.077V4.09c.81-.03 1.577-.13 2.282-.287z"></path></svg>'
|
||||
),
|
||||
"class": "",
|
||||
},
|
||||
],
|
||||
@@ -304,5 +320,8 @@ from docs.auxil.tg_const_role import CONSTANTS_ROLE, TGConstXRefRole
|
||||
def setup(app: Sphinx):
|
||||
app.connect("autodoc-skip-member", autodoc_skip_member)
|
||||
app.connect("autodoc-process-bases", autodoc_process_bases)
|
||||
app.connect("autodoc-process-docstring", autodoc_process_docstring)
|
||||
# The default priority is 500. We want our function to run before napoleon doc-conversion
|
||||
# and sphinx-paramlinks do, b/c otherwise the inserted kwargs in the bot methods won't show
|
||||
# up in the objects.inv file that Sphinx generates (i.e. not in the search).
|
||||
app.connect("autodoc-process-docstring", autodoc_process_docstring, priority=100)
|
||||
app.add_role_to_domain("py", CONSTANTS_ROLE, TGConstXRefRole())
|
||||
|
||||
@@ -4,4 +4,4 @@ Bot
|
||||
.. autoclass:: telegram.Bot
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members: __reduce__, __deepcopy__
|
||||
:special-members: __repr__, __reduce__, __deepcopy__
|
||||
@@ -4,3 +4,4 @@ Application
|
||||
.. autoclass:: telegram.ext.Application
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members: __repr__
|
||||
|
||||
@@ -4,3 +4,4 @@ BaseHandler
|
||||
.. autoclass:: telegram.ext.BaseHandler
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members: __repr__
|
||||
|
||||
@@ -4,3 +4,4 @@ ConversationHandler
|
||||
.. autoclass:: telegram.ext.ConversationHandler
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members: __repr__
|
||||
|
||||
@@ -4,3 +4,4 @@ ExtBot
|
||||
.. autoclass:: telegram.ext.ExtBot
|
||||
:show-inheritance:
|
||||
:members: insert_callback_data, defaults, rate_limiter, initialize, shutdown, callback_data_cache
|
||||
:special-members: __repr__
|
||||
|
||||
@@ -4,4 +4,4 @@ Job
|
||||
.. autoclass:: telegram.ext.Job
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members: __call__
|
||||
:special-members: __call__, __repr__
|
||||
|
||||
@@ -4,3 +4,4 @@ JobQueue
|
||||
.. autoclass:: telegram.ext.JobQueue
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members: __repr__
|
||||
|
||||
@@ -4,3 +4,4 @@ Updater
|
||||
.. autoclass:: telegram.ext.Updater
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members: __repr__
|
||||
|
||||
@@ -61,3 +61,5 @@
|
||||
.. |removed_thumb_url_note| replace:: Removed the deprecated argument and attribute ``thumb_url``.
|
||||
|
||||
.. |removed_thumb_wildcard_note| replace:: Removed the deprecated arguments and attributes ``thumb_*``.
|
||||
|
||||
.. |async_context_manager| replace:: Asynchronous context manager which
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""This example showcases how PTBs "arbitrary callback data" feature can be used.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -115,8 +115,7 @@ async def count_click(update: Update, context: CustomContext) -> None:
|
||||
async def print_users(update: Update, context: CustomContext) -> None:
|
||||
"""Show which users have been using this bot."""
|
||||
await update.message.reply_text(
|
||||
"The following user IDs have used this bot: "
|
||||
f'{", ".join(map(str, context.bot_user_ids))}'
|
||||
f"The following user IDs have used this bot: {', '.join(map(str, context.bot_user_ids))}"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""Bot that explains Telegram's "Deep Linking Parameters" functionality.
|
||||
@@ -57,8 +57,7 @@ async def deep_linked_level_1(update: Update, context: ContextTypes.DEFAULT_TYPE
|
||||
bot = context.bot
|
||||
url = helpers.create_deep_linked_url(bot.username, SO_COOL)
|
||||
text = (
|
||||
"Awesome, you just accessed hidden functionality! "
|
||||
"Now let's get back to the private chat."
|
||||
"Awesome, you just accessed hidden functionality! Now let's get back to the private chat."
|
||||
)
|
||||
keyboard = InlineKeyboardMarkup.from_button(
|
||||
InlineKeyboardButton(text="Continue here!", url=url)
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""This is a very simple example on how one could implement a custom error handler."""
|
||||
@@ -40,7 +40,7 @@ async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> N
|
||||
# You might need to add some logic to deal with messages longer than the 4096 character limit.
|
||||
update_str = update.to_dict() if isinstance(update, Update) else str(update)
|
||||
message = (
|
||||
f"An exception was raised while handling an update\n"
|
||||
"An exception was raised while handling an update\n"
|
||||
f"<pre>update = {html.escape(json.dumps(update_str, indent=2, ensure_ascii=False))}"
|
||||
"</pre>\n\n"
|
||||
f"<pre>context.chat_data = {html.escape(str(context.chat_data))}</pre>\n\n"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""Simple inline keyboard bot with multiple CallbackQueryHandlers.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""Basic example for a bot that can receive payment from user."""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -59,7 +59,7 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||||
if context.user_data:
|
||||
reply_text += (
|
||||
f" You already told me your {', '.join(context.user_data.keys())}. Why don't you "
|
||||
f"tell me something more about yourself? Or change anything I already know."
|
||||
"tell me something more about yourself? Or change anything I already know."
|
||||
)
|
||||
else:
|
||||
reply_text += (
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=import-error
|
||||
"""Simple Bot to reply to Telegram messages.
|
||||
|
||||
This is built on the API wrapper, see echobot.py to see the same example built
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument, import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=unused-argument,import-error
|
||||
# pylint: disable=unused-argument
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
@@ -45,8 +45,10 @@ async def web_app_data(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
|
||||
# (see webappbot.html)
|
||||
data = json.loads(update.effective_message.web_app_data.data)
|
||||
await update.message.reply_html(
|
||||
text=f"You selected the color with the HEX value <code>{data['hex']}</code>. The "
|
||||
f"corresponding RGB value is <code>{tuple(data['rgb'].values())}</code>.",
|
||||
text=(
|
||||
f"You selected the color with the HEX value <code>{data['hex']}</code>. The "
|
||||
f"corresponding RGB value is <code>{tuple(data['rgb'].values())}</code>."
|
||||
),
|
||||
reply_markup=ReplyKeyboardRemove(),
|
||||
)
|
||||
|
||||
|
||||
+2
-3
@@ -12,10 +12,9 @@ target-version = "py38"
|
||||
show-fixes = true
|
||||
ignore = ["PLR2004", "PLR0911", "PLR0912", "PLR0913", "PLR0915", "PERF203"]
|
||||
select = ["E", "F", "I", "PL", "UP", "RUF", "PTH", "C4", "B", "PIE", "SIM", "RET", "RSE",
|
||||
"G", "ISC", "PT", "ASYNC", "TCH", "CPY", "SLOT", "PERF", "PYI"]
|
||||
"G", "ISC", "PT", "ASYNC", "TCH", "SLOT", "PERF", "PYI", "FLY", "AIR"]
|
||||
# Add "FURB" after it's out of preview
|
||||
|
||||
[tool.ruff.per-file-ignores]
|
||||
"tests/*.py" = ["B018"]
|
||||
"**/__init__.py" = ["CPY001"]
|
||||
"examples/**.py" = ["CPY001"]
|
||||
"tests/**.py" = ["RUF012"]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
pre-commit # needed for pre-commit hooks in the git commit command
|
||||
|
||||
# For the test suite
|
||||
pytest==7.4.0
|
||||
pytest==7.4.3
|
||||
pytest-asyncio==0.21.1 # needed because pytest doesn't come with native support for coroutines as tests
|
||||
pytest-xdist==3.3.1 # xdist runs tests in parallel
|
||||
pytest-xdist==3.5.0 # xdist runs tests in parallel
|
||||
flaky # Used for flaky tests (flaky decorator)
|
||||
beautifulsoup4 # used in test_official for parsing tg docs
|
||||
|
||||
|
||||
@@ -16,11 +16,11 @@ 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.2 # webhooks!ext
|
||||
tornado~=6.3.3 # webhooks!ext
|
||||
|
||||
# Cachetools and APS don't have a strict stability policy.
|
||||
# Let's be cautious for now.
|
||||
cachetools~=5.3.1 # callback-data!ext
|
||||
cachetools~=5.3.2 # callback-data!ext
|
||||
APScheduler~=3.10.4 # job-queue!ext
|
||||
|
||||
# pytz is required by APS and just needs the lower bound due to #2120
|
||||
|
||||
+1
-1
@@ -6,4 +6,4 @@
|
||||
# versions and only increase the lower bound if necessary
|
||||
|
||||
# httpx has no stable release yet, so let's be cautious for now
|
||||
httpx ~= 0.24.1
|
||||
httpx ~= 0.25.2
|
||||
|
||||
@@ -19,7 +19,7 @@ exclude = setup.py, setup-raw.py docs/source/conf.py
|
||||
disable = duplicate-code,too-many-arguments,too-many-public-methods,too-few-public-methods,
|
||||
broad-except,too-many-instance-attributes,fixme,missing-function-docstring,
|
||||
missing-class-docstring,too-many-locals,too-many-lines,too-many-branches,
|
||||
too-many-statements
|
||||
too-many-statements, cyclic-import
|
||||
enable=useless-suppression ; Warns about unused pylint ignores
|
||||
exclude-protected=_unfrozen
|
||||
|
||||
|
||||
+274
-222
@@ -69,7 +69,6 @@ from telegram._files.contact import Contact
|
||||
from telegram._files.document import Document
|
||||
from telegram._files.file import File
|
||||
from telegram._files.inputmedia import InputMedia
|
||||
from telegram._files.inputsticker import InputSticker
|
||||
from telegram._files.location import Location
|
||||
from telegram._files.photosize import PhotoSize
|
||||
from telegram._files.sticker import MaskPosition, Sticker, StickerSet
|
||||
@@ -79,13 +78,10 @@ from telegram._files.videonote import VideoNote
|
||||
from telegram._files.voice import Voice
|
||||
from telegram._forumtopic import ForumTopic
|
||||
from telegram._games.gamehighscore import GameHighScore
|
||||
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
|
||||
from telegram._menubutton import MenuButton
|
||||
from telegram._message import Message
|
||||
from telegram._messageid import MessageId
|
||||
from telegram._passport.passportelementerrors import PassportElementError
|
||||
from telegram._payment.shippingoption import ShippingOption
|
||||
from telegram._poll import Poll
|
||||
from telegram._sentwebappmessage import SentWebAppMessage
|
||||
from telegram._telegramobject import TelegramObject
|
||||
@@ -96,14 +92,8 @@ from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
|
||||
from telegram._utils.files import is_local_file, parse_file_input
|
||||
from telegram._utils.logging import get_logger
|
||||
from telegram._utils.types import (
|
||||
CorrectOptionID,
|
||||
DVInput,
|
||||
FileInput,
|
||||
JSONDict,
|
||||
ODVInput,
|
||||
ReplyMarkup,
|
||||
)
|
||||
from telegram._utils.repr import build_repr_with_selected_attrs
|
||||
from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram._webhookinfo import WebhookInfo
|
||||
from telegram.constants import InlineQueryLimit
|
||||
@@ -111,18 +101,22 @@ from telegram.error import InvalidToken
|
||||
from telegram.request import BaseRequest, RequestData
|
||||
from telegram.request._httpxrequest import HTTPXRequest
|
||||
from telegram.request._requestparameter import RequestParameter
|
||||
from telegram.warnings import PTBUserWarning
|
||||
from telegram.warnings import PTBDeprecationWarning, PTBUserWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import (
|
||||
InlineKeyboardMarkup,
|
||||
InlineQueryResult,
|
||||
InputFile,
|
||||
InputMediaAudio,
|
||||
InputMediaDocument,
|
||||
InputMediaPhoto,
|
||||
InputMediaVideo,
|
||||
InputSticker,
|
||||
LabeledPrice,
|
||||
MessageEntity,
|
||||
PassportElementError,
|
||||
ShippingOption,
|
||||
)
|
||||
|
||||
BT = TypeVar("BT", bound="Bot")
|
||||
@@ -148,6 +142,8 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
finally:
|
||||
await bot.shutdown()
|
||||
|
||||
.. seealso:: :meth:`__aenter__` and :meth:`__aexit__`.
|
||||
|
||||
Note:
|
||||
* Most bot methods have the argument ``api_kwargs`` which allows passing arbitrary keywords
|
||||
to the Telegram API. This can be used to access new features of the API before they are
|
||||
@@ -290,8 +286,8 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
if warning_string:
|
||||
self._warn(
|
||||
f"You set the HTTP version for the {warning_string} HTTPXRequest instance to "
|
||||
f"HTTP/2. The self hosted bot api instances only support HTTP/1.1. You should "
|
||||
f"either run a HTTP proxy in front of it which supports HTTP/2 or use HTTP/1.1.",
|
||||
"HTTP/2. The self hosted bot api instances only support HTTP/1.1. You should "
|
||||
"either run a HTTP proxy in front of it which supports HTTP/2 or use HTTP/1.1.",
|
||||
PTBUserWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
@@ -308,6 +304,76 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
|
||||
self._freeze()
|
||||
|
||||
async def __aenter__(self: BT) -> BT:
|
||||
"""
|
||||
|async_context_manager| :meth:`initializes <initialize>` the Bot.
|
||||
|
||||
Returns:
|
||||
The initialized Bot instance.
|
||||
|
||||
Raises:
|
||||
:exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown`
|
||||
is called in this case.
|
||||
"""
|
||||
try:
|
||||
await self.initialize()
|
||||
return self
|
||||
except Exception as exc:
|
||||
await self.shutdown()
|
||||
raise exc
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[Type[BaseException]],
|
||||
exc_val: Optional[BaseException],
|
||||
exc_tb: Optional[TracebackType],
|
||||
) -> None:
|
||||
"""|async_context_manager| :meth:`shuts down <shutdown>` the Bot."""
|
||||
# Make sure not to return `True` so that exceptions are not suppressed
|
||||
# https://docs.python.org/3/reference/datamodel.html?#object.__aexit__
|
||||
await self.shutdown()
|
||||
|
||||
def __reduce__(self) -> NoReturn:
|
||||
"""Customizes how :func:`copy.deepcopy` processes objects of this type. Bots can not
|
||||
be pickled and this method will always raise an exception.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
|
||||
Raises:
|
||||
:exc:`pickle.PicklingError`
|
||||
"""
|
||||
raise pickle.PicklingError("Bot objects cannot be pickled!")
|
||||
|
||||
def __deepcopy__(self, memodict: Dict[int, object]) -> NoReturn:
|
||||
"""Customizes how :func:`copy.deepcopy` processes objects of this type. Bots can not
|
||||
be deepcopied and this method will always raise an exception.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
|
||||
Raises:
|
||||
:exc:`TypeError`
|
||||
"""
|
||||
raise TypeError("Bot objects cannot be deepcopied!")
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, self.__class__):
|
||||
return self.bot == other.bot
|
||||
return False
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.__class__, self.bot))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Give a string representation of the bot in the form ``Bot[token=...]``.
|
||||
|
||||
As this class doesn't implement :meth:`object.__str__`, the default implementation
|
||||
will be used, which is equivalent to :meth:`__repr__`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`
|
||||
"""
|
||||
return build_repr_with_selected_attrs(self, token=self.token)
|
||||
|
||||
@property
|
||||
def token(self) -> str:
|
||||
""":obj:`str`: Bot's unique authentication token.
|
||||
@@ -353,6 +419,93 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
"""
|
||||
return self._private_key
|
||||
|
||||
@property
|
||||
def request(self) -> BaseRequest:
|
||||
"""The :class:`~telegram.request.BaseRequest` object used by this bot.
|
||||
|
||||
Warning:
|
||||
Requests to the Bot API are made by the various methods of this class. This attribute
|
||||
should *not* be used manually.
|
||||
"""
|
||||
return self._request[1]
|
||||
|
||||
@property
|
||||
def bot(self) -> User:
|
||||
""":class:`telegram.User`: User instance for the bot as returned by :meth:`get_me`.
|
||||
|
||||
Warning:
|
||||
This value is the cached return value of :meth:`get_me`. If the bots profile is
|
||||
changed during runtime, this value won't reflect the changes until :meth:`get_me` is
|
||||
called again.
|
||||
|
||||
.. seealso:: :meth:`initialize`
|
||||
"""
|
||||
if self._bot_user is None:
|
||||
raise RuntimeError(
|
||||
f"{self.__class__.__name__} is not properly initialized. Call "
|
||||
f"`{self.__class__.__name__}.initialize` before accessing this property."
|
||||
)
|
||||
return self._bot_user
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
""":obj:`int`: Unique identifier for this bot. Shortcut for the corresponding attribute of
|
||||
:attr:`bot`.
|
||||
"""
|
||||
return self.bot.id
|
||||
|
||||
@property
|
||||
def first_name(self) -> str:
|
||||
""":obj:`str`: Bot's first name. Shortcut for the corresponding attribute of
|
||||
:attr:`bot`.
|
||||
"""
|
||||
return self.bot.first_name
|
||||
|
||||
@property
|
||||
def last_name(self) -> str:
|
||||
""":obj:`str`: Optional. Bot's last name. Shortcut for the corresponding attribute of
|
||||
:attr:`bot`.
|
||||
"""
|
||||
return self.bot.last_name # type: ignore
|
||||
|
||||
@property
|
||||
def username(self) -> str:
|
||||
""":obj:`str`: Bot's username. Shortcut for the corresponding attribute of
|
||||
:attr:`bot`.
|
||||
"""
|
||||
return self.bot.username # type: ignore
|
||||
|
||||
@property
|
||||
def link(self) -> str:
|
||||
""":obj:`str`: Convenience property. Returns the t.me link of the bot."""
|
||||
return f"https://t.me/{self.username}"
|
||||
|
||||
@property
|
||||
def can_join_groups(self) -> bool:
|
||||
""":obj:`bool`: Bot's :attr:`telegram.User.can_join_groups` attribute. Shortcut for the
|
||||
corresponding attribute of :attr:`bot`.
|
||||
"""
|
||||
return self.bot.can_join_groups # type: ignore
|
||||
|
||||
@property
|
||||
def can_read_all_group_messages(self) -> bool:
|
||||
""":obj:`bool`: Bot's :attr:`telegram.User.can_read_all_group_messages` attribute.
|
||||
Shortcut for the corresponding attribute of :attr:`bot`.
|
||||
"""
|
||||
return self.bot.can_read_all_group_messages # type: ignore
|
||||
|
||||
@property
|
||||
def supports_inline_queries(self) -> bool:
|
||||
""":obj:`bool`: Bot's :attr:`telegram.User.supports_inline_queries` attribute.
|
||||
Shortcut for the corresponding attribute of :attr:`bot`.
|
||||
"""
|
||||
return self.bot.supports_inline_queries # type: ignore
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
""":obj:`str`: Bot's @username. Shortcut for the corresponding attribute of :attr:`bot`."""
|
||||
return f"@{self.username}"
|
||||
|
||||
@classmethod
|
||||
def _warn(
|
||||
cls, message: str, category: Type[Warning] = PTBUserWarning, stacklevel: int = 0
|
||||
@@ -362,28 +515,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
"""
|
||||
warn(message=message, category=category, stacklevel=stacklevel + 1)
|
||||
|
||||
def __reduce__(self) -> NoReturn:
|
||||
"""Customizes how :func:`copy.deepcopy` processes objects of this type. Bots can not
|
||||
be pickled and this method will always raise an exception.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
|
||||
Raises:
|
||||
:exc:`pickle.PicklingError`
|
||||
"""
|
||||
raise pickle.PicklingError("Bot objects cannot be pickled!")
|
||||
|
||||
def __deepcopy__(self, memodict: Dict[int, object]) -> NoReturn:
|
||||
"""Customizes how :func:`copy.deepcopy` processes objects of this type. Bots can not
|
||||
be deepcopied and this method will always raise an exception.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
|
||||
Raises:
|
||||
:exc:`TypeError`
|
||||
"""
|
||||
raise TypeError("Bot objects cannot be deepcopied!")
|
||||
|
||||
# TODO: After https://youtrack.jetbrains.com/issue/PY-50952 is fixed, we can revisit this and
|
||||
# consider adding Paramspec from typing_extensions to properly fix this. Currently a workaround
|
||||
def _log(func: Any): # type: ignore[no-untyped-def] # skipcq: PY-D0003
|
||||
@@ -621,111 +752,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
await asyncio.gather(self._request[0].shutdown(), self._request[1].shutdown())
|
||||
self._initialized = False
|
||||
|
||||
async def __aenter__(self: BT) -> BT:
|
||||
try:
|
||||
await self.initialize()
|
||||
return self
|
||||
except Exception as exc:
|
||||
await self.shutdown()
|
||||
raise exc
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[Type[BaseException]],
|
||||
exc_val: Optional[BaseException],
|
||||
exc_tb: Optional[TracebackType],
|
||||
) -> None:
|
||||
# Make sure not to return `True` so that exceptions are not suppressed
|
||||
# https://docs.python.org/3/reference/datamodel.html?#object.__aexit__
|
||||
await self.shutdown()
|
||||
|
||||
@property
|
||||
def request(self) -> BaseRequest:
|
||||
"""The :class:`~telegram.request.BaseRequest` object used by this bot.
|
||||
|
||||
Warning:
|
||||
Requests to the Bot API are made by the various methods of this class. This attribute
|
||||
should *not* be used manually.
|
||||
"""
|
||||
return self._request[1]
|
||||
|
||||
@property
|
||||
def bot(self) -> User:
|
||||
""":class:`telegram.User`: User instance for the bot as returned by :meth:`get_me`.
|
||||
|
||||
Warning:
|
||||
This value is the cached return value of :meth:`get_me`. If the bots profile is
|
||||
changed during runtime, this value won't reflect the changes until :meth:`get_me` is
|
||||
called again.
|
||||
|
||||
.. seealso:: :meth:`initialize`
|
||||
"""
|
||||
if self._bot_user is None:
|
||||
raise RuntimeError(
|
||||
f"{self.__class__.__name__} is not properly initialized. Call "
|
||||
f"`{self.__class__.__name__}.initialize` before accessing this property."
|
||||
)
|
||||
return self._bot_user
|
||||
|
||||
@property
|
||||
def id(self) -> int: # pylint: disable=invalid-name
|
||||
""":obj:`int`: Unique identifier for this bot. Shortcut for the corresponding attribute of
|
||||
:attr:`bot`.
|
||||
"""
|
||||
return self.bot.id
|
||||
|
||||
@property
|
||||
def first_name(self) -> str:
|
||||
""":obj:`str`: Bot's first name. Shortcut for the corresponding attribute of
|
||||
:attr:`bot`.
|
||||
"""
|
||||
return self.bot.first_name
|
||||
|
||||
@property
|
||||
def last_name(self) -> str:
|
||||
""":obj:`str`: Optional. Bot's last name. Shortcut for the corresponding attribute of
|
||||
:attr:`bot`.
|
||||
"""
|
||||
return self.bot.last_name # type: ignore
|
||||
|
||||
@property
|
||||
def username(self) -> str:
|
||||
""":obj:`str`: Bot's username. Shortcut for the corresponding attribute of
|
||||
:attr:`bot`.
|
||||
"""
|
||||
return self.bot.username # type: ignore
|
||||
|
||||
@property
|
||||
def link(self) -> str:
|
||||
""":obj:`str`: Convenience property. Returns the t.me link of the bot."""
|
||||
return f"https://t.me/{self.username}"
|
||||
|
||||
@property
|
||||
def can_join_groups(self) -> bool:
|
||||
""":obj:`bool`: Bot's :attr:`telegram.User.can_join_groups` attribute. Shortcut for the
|
||||
corresponding attribute of :attr:`bot`.
|
||||
"""
|
||||
return self.bot.can_join_groups # type: ignore
|
||||
|
||||
@property
|
||||
def can_read_all_group_messages(self) -> bool:
|
||||
""":obj:`bool`: Bot's :attr:`telegram.User.can_read_all_group_messages` attribute.
|
||||
Shortcut for the corresponding attribute of :attr:`bot`.
|
||||
"""
|
||||
return self.bot.can_read_all_group_messages # type: ignore
|
||||
|
||||
@property
|
||||
def supports_inline_queries(self) -> bool:
|
||||
""":obj:`bool`: Bot's :attr:`telegram.User.supports_inline_queries` attribute.
|
||||
Shortcut for the corresponding attribute of :attr:`bot`.
|
||||
"""
|
||||
return self.bot.supports_inline_queries # type: ignore
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
""":obj:`str`: Bot's @username. Shortcut for the corresponding attribute of :attr:`bot`."""
|
||||
return f"@{self.username}"
|
||||
|
||||
@_log
|
||||
async def get_me(
|
||||
self,
|
||||
@@ -765,7 +791,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -900,7 +926,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
chat_id: Union[int, str],
|
||||
from_chat_id: Union[str, int],
|
||||
message_id: int,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
*,
|
||||
@@ -966,7 +992,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
chat_id: Union[int, str],
|
||||
photo: Union[FileInput, "PhotoSize"],
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -978,7 +1004,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1080,7 +1106,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
performer: Optional[str] = None,
|
||||
title: Optional[str] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -1092,7 +1118,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1204,7 +1230,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
chat_id: Union[int, str],
|
||||
document: Union[FileInput, "Document"],
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -1217,7 +1243,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1323,7 +1349,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
sticker: Union[FileInput, "Sticker"],
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1332,7 +1358,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
emoji: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1411,7 +1437,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
video: Union[FileInput, "Video"],
|
||||
duration: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
width: Optional[int] = None,
|
||||
@@ -1427,7 +1453,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1550,7 +1576,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
video_note: Union[FileInput, "VideoNote"],
|
||||
duration: Optional[int] = None,
|
||||
length: Optional[int] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1560,7 +1586,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1665,7 +1691,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
height: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1677,7 +1703,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1793,7 +1819,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
voice: Union[FileInput, "Voice"],
|
||||
duration: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -1804,7 +1830,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1916,7 +1942,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
message_thread_id: Optional[int] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2037,7 +2063,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
chat_id: Union[int, str],
|
||||
latitude: Optional[float] = None,
|
||||
longitude: Optional[float] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
live_period: Optional[int] = None,
|
||||
@@ -2154,7 +2180,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
inline_message_id: Optional[str] = None,
|
||||
latitude: Optional[float] = None,
|
||||
longitude: Optional[float] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
horizontal_accuracy: Optional[float] = None,
|
||||
heading: Optional[int] = None,
|
||||
proximity_alert_radius: Optional[int] = None,
|
||||
@@ -2247,7 +2273,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
chat_id: Optional[Union[str, int]] = None,
|
||||
message_id: Optional[int] = None,
|
||||
inline_message_id: Optional[str] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2298,7 +2324,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
title: Optional[str] = None,
|
||||
address: Optional[str] = None,
|
||||
foursquare_id: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
foursquare_type: Optional[str] = None,
|
||||
@@ -2422,7 +2448,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
phone_number: Optional[str] = None,
|
||||
first_name: Optional[str] = None,
|
||||
last_name: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
vcard: Optional[str] = None,
|
||||
@@ -2521,11 +2547,11 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
@_log
|
||||
async def send_game(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
chat_id: int,
|
||||
game_short_name: str,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
@@ -2539,7 +2565,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
"""Use this method to send a game.
|
||||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat.
|
||||
chat_id (:obj:`int`): Unique identifier for the target chat.
|
||||
game_short_name (:obj:`str`): Short name of the game, serves as the unique identifier
|
||||
for the game. Set up your games via `@BotFather <https://t.me/BotFather>`_.
|
||||
disable_notification (:obj:`bool`, optional): |disable_notification|
|
||||
@@ -2826,7 +2852,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
@_log
|
||||
async def get_user_profile_photos(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
offset: Optional[int] = None,
|
||||
limit: Optional[int] = None,
|
||||
*,
|
||||
@@ -2938,7 +2964,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
async def ban_chat_member(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
until_date: Optional[Union[int, datetime]] = None,
|
||||
revoke_messages: Optional[bool] = None,
|
||||
*,
|
||||
@@ -3046,7 +3072,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
async def unban_chat_member(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
only_if_banned: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -3203,7 +3229,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
inline_message_id: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -3279,7 +3305,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
message_id: Optional[int] = None,
|
||||
inline_message_id: Optional[str] = None,
|
||||
caption: Optional[str] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
*,
|
||||
@@ -3349,7 +3375,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
chat_id: Optional[Union[str, int]] = None,
|
||||
message_id: Optional[int] = None,
|
||||
inline_message_id: Optional[str] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -3470,7 +3496,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
timeout: Optional[int] = None,
|
||||
allowed_updates: Optional[Sequence[str]] = None,
|
||||
*,
|
||||
read_timeout: float = 2,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -3532,6 +3558,22 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
"allowed_updates": allowed_updates,
|
||||
}
|
||||
|
||||
# The "or 0" is needed for the case where read_timeout is None.
|
||||
if not isinstance(read_timeout, DefaultValue):
|
||||
arg_read_timeout: float = read_timeout or 0
|
||||
else:
|
||||
try:
|
||||
arg_read_timeout = self._request[0].read_timeout or 0
|
||||
except NotImplementedError:
|
||||
arg_read_timeout = 2
|
||||
self._warn(
|
||||
f"The class {self._request[0].__class__.__name__} does not override "
|
||||
"the property `read_timeout`. Overriding this property will be mandatory in "
|
||||
"future versions. Using 2 seconds as fallback.",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel=3,
|
||||
)
|
||||
|
||||
# Ideally we'd use an aggressive read timeout for the polling. However,
|
||||
# * Short polling should return within 2 seconds.
|
||||
# * Long polling poses a different problem: the connection might have been dropped while
|
||||
@@ -3542,7 +3584,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
await self._post(
|
||||
"getUpdates",
|
||||
data,
|
||||
read_timeout=read_timeout + timeout if timeout else read_timeout,
|
||||
read_timeout=arg_read_timeout + timeout if timeout else arg_read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
@@ -3876,7 +3918,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
async def get_chat_member(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -4011,9 +4053,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
@_log
|
||||
async def set_game_score(
|
||||
self,
|
||||
user_id: Union[int, str],
|
||||
user_id: int,
|
||||
score: int,
|
||||
chat_id: Optional[Union[str, int]] = None,
|
||||
chat_id: Optional[int] = None,
|
||||
message_id: Optional[int] = None,
|
||||
inline_message_id: Optional[str] = None,
|
||||
force: Optional[bool] = None,
|
||||
@@ -4037,7 +4079,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
decrease. This can be useful when fixing mistakes or banning cheaters.
|
||||
disable_edit_message (:obj:`bool`, optional): Pass :obj:`True`, if the game message
|
||||
should not be automatically edited to include the current scoreboard.
|
||||
chat_id (:obj:`int` | :obj:`str`, optional): Required if :paramref:`inline_message_id`
|
||||
chat_id (:obj:`int`, optional): Required if :paramref:`inline_message_id`
|
||||
is not specified. Unique identifier for the target chat.
|
||||
message_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` is not
|
||||
specified. Identifier of the sent message.
|
||||
@@ -4076,8 +4118,8 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
@_log
|
||||
async def get_game_high_scores(
|
||||
self,
|
||||
user_id: Union[int, str],
|
||||
chat_id: Optional[Union[str, int]] = None,
|
||||
user_id: int,
|
||||
chat_id: Optional[int] = None,
|
||||
message_id: Optional[int] = None,
|
||||
inline_message_id: Optional[str] = None,
|
||||
*,
|
||||
@@ -4101,7 +4143,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
|
||||
Args:
|
||||
user_id (:obj:`int`): Target user id.
|
||||
chat_id (:obj:`int` | :obj:`str`, optional): Required if :paramref:`inline_message_id`
|
||||
chat_id (:obj:`int`, optional): Required if :paramref:`inline_message_id`
|
||||
is not specified. Unique identifier for the target chat.
|
||||
message_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` is not
|
||||
specified. Identifier of the sent message.
|
||||
@@ -4154,9 +4196,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
need_email: Optional[bool] = None,
|
||||
need_shipping_address: Optional[bool] = None,
|
||||
is_flexible: Optional[bool] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
provider_data: Optional[Union[str, object]] = None,
|
||||
send_phone_number_to_provider: Optional[bool] = None,
|
||||
send_email_to_provider: Optional[bool] = None,
|
||||
@@ -4317,11 +4359,11 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
)
|
||||
|
||||
@_log
|
||||
async def answer_shipping_query( # pylint: disable=invalid-name
|
||||
async def answer_shipping_query(
|
||||
self,
|
||||
shipping_query_id: str,
|
||||
ok: bool,
|
||||
shipping_options: Optional[Sequence[ShippingOption]] = None,
|
||||
shipping_options: Optional[Sequence["ShippingOption"]] = None,
|
||||
error_message: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -4376,7 +4418,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
)
|
||||
|
||||
@_log
|
||||
async def answer_pre_checkout_query( # pylint: disable=invalid-name
|
||||
async def answer_pre_checkout_query(
|
||||
self,
|
||||
pre_checkout_query_id: str,
|
||||
ok: bool,
|
||||
@@ -4483,7 +4525,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
async def restrict_chat_member(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
permissions: ChatPermissions,
|
||||
until_date: Optional[Union[int, datetime]] = None,
|
||||
use_independent_chat_permissions: Optional[bool] = None,
|
||||
@@ -4557,7 +4599,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
async def promote_chat_member(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
can_change_info: Optional[bool] = None,
|
||||
can_post_messages: Optional[bool] = None,
|
||||
can_edit_messages: Optional[bool] = None,
|
||||
@@ -4570,6 +4612,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
can_manage_chat: Optional[bool] = None,
|
||||
can_manage_video_chats: Optional[bool] = None,
|
||||
can_manage_topics: Optional[bool] = None,
|
||||
can_post_stories: Optional[bool] = None,
|
||||
can_edit_stories: Optional[bool] = None,
|
||||
can_delete_stories: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -4591,10 +4636,10 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
user_id (:obj:`int`): Unique identifier of the target user.
|
||||
is_anonymous (:obj:`bool`, optional): Pass :obj:`True`, if the administrator's presence
|
||||
in the chat is hidden.
|
||||
can_manage_chat (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
access the chat event log, chat statistics, message statistics in channels, see
|
||||
channel members, see anonymous administrators in supergroups and ignore slow mode.
|
||||
Implied by any other administrator privilege.
|
||||
can_manage_chat (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
access the chat event log, chat statistics, boost list in channels, see channel
|
||||
members, report spam messages, see anonymous administrators in supergroups and
|
||||
ignore slow mode. Implied by any other administrator privilege.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
@@ -4606,7 +4651,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
can_change_info (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
change chat title, photo and other settings.
|
||||
can_post_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
create channel posts, channels only.
|
||||
post messages in the channel, or access channel statistics; channels only.
|
||||
can_edit_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
edit messages of other users and can pin messages, channels only.
|
||||
can_delete_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
@@ -4614,7 +4659,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
can_invite_users (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
invite new users to the chat.
|
||||
can_restrict_members (:obj:`bool`, optional): Pass :obj:`True`, if the administrator
|
||||
can restrict, ban or unban chat members.
|
||||
can restrict, ban or unban chat members, or access supergroup statistics.
|
||||
can_pin_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
pin messages, supergroups only.
|
||||
can_promote_members (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
@@ -4625,6 +4670,18 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
allowed to create, rename, close, and reopen forum topics; supergroups only.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
can_post_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
post stories in the channel; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_edit_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
edit stories posted by other users; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_delete_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
delete stories posted by other users; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
@@ -4648,6 +4705,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
"can_manage_chat": can_manage_chat,
|
||||
"can_manage_video_chats": can_manage_video_chats,
|
||||
"can_manage_topics": can_manage_topics,
|
||||
"can_post_stories": can_post_stories,
|
||||
"can_edit_stories": can_edit_stories,
|
||||
"can_delete_stories": can_delete_stories,
|
||||
}
|
||||
|
||||
return await self._post(
|
||||
@@ -4723,7 +4783,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
async def set_chat_administrator_custom_title(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
user_id: Union[int, str],
|
||||
user_id: int,
|
||||
custom_title: str,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -5103,7 +5163,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||
photo: FileInput,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -5478,12 +5538,12 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||
@_log
|
||||
async def upload_sticker_file(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
sticker: Optional[FileInput],
|
||||
sticker_format: Optional[str],
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -5538,12 +5598,12 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||
@_log
|
||||
async def add_sticker_to_set(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
name: str,
|
||||
sticker: Optional[InputSticker],
|
||||
sticker: Optional["InputSticker"],
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -5636,16 +5696,16 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||
@_log
|
||||
async def create_new_sticker_set(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
name: str,
|
||||
title: str,
|
||||
stickers: Optional[Sequence[InputSticker]],
|
||||
stickers: Optional[Sequence["InputSticker"]],
|
||||
sticker_format: Optional[str],
|
||||
sticker_type: Optional[str] = None,
|
||||
needs_repainting: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -5807,7 +5867,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||
async def set_sticker_set_thumbnail(
|
||||
self,
|
||||
name: str,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -6079,8 +6139,8 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||
@_log
|
||||
async def set_passport_data_errors(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
errors: Sequence[PassportElementError],
|
||||
user_id: int,
|
||||
errors: Sequence["PassportElementError"],
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -6262,7 +6322,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
message_id: int,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -6709,9 +6769,9 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
@@ -7843,14 +7903,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||
|
||||
return data
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, self.__class__):
|
||||
return self.bot == other.bot
|
||||
return False
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.__class__, self.bot))
|
||||
|
||||
# camelCase aliases
|
||||
getMe = get_me
|
||||
"""Alias for :meth:`get_me`"""
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram._message import Message
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import DVInput, JSONDict, ODVInput, ReplyMarkup
|
||||
from telegram._utils.types import JSONDict, ODVInput, ReplyMarkup
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import (
|
||||
@@ -127,7 +127,7 @@ class CallbackQuery(TelegramObject):
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Required
|
||||
self.id: str = id # pylint: disable=invalid-name
|
||||
self.id: str = id
|
||||
self.from_user: User = from_user
|
||||
self.chat_instance: str = chat_instance
|
||||
# Optionals
|
||||
@@ -531,7 +531,7 @@ class CallbackQuery(TelegramObject):
|
||||
|
||||
async def set_game_score(
|
||||
self,
|
||||
user_id: Union[int, str],
|
||||
user_id: int,
|
||||
score: int,
|
||||
force: Optional[bool] = None,
|
||||
disable_edit_message: Optional[bool] = None,
|
||||
@@ -589,7 +589,7 @@ class CallbackQuery(TelegramObject):
|
||||
|
||||
async def get_game_high_scores(
|
||||
self,
|
||||
user_id: Union[int, str],
|
||||
user_id: int,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -725,9 +725,9 @@ class CallbackQuery(TelegramObject):
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
|
||||
+46
-44
@@ -33,14 +33,7 @@ from telegram._utils import enum
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import (
|
||||
CorrectOptionID,
|
||||
DVInput,
|
||||
FileInput,
|
||||
JSONDict,
|
||||
ODVInput,
|
||||
ReplyMarkup,
|
||||
)
|
||||
from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup
|
||||
from telegram.helpers import escape_markdown
|
||||
from telegram.helpers import mention_html as helpers_mention_html
|
||||
from telegram.helpers import mention_markdown as helpers_mention_markdown
|
||||
@@ -374,7 +367,7 @@ class Chat(TelegramObject):
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Required
|
||||
self.id: int = id # pylint: disable=invalid-name
|
||||
self.id: int = id
|
||||
self.type: str = enum.get_member(constants.ChatType, type, type)
|
||||
# Optionals
|
||||
self.title: Optional[str] = title
|
||||
@@ -677,7 +670,7 @@ class Chat(TelegramObject):
|
||||
|
||||
async def get_member(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -707,7 +700,7 @@ class Chat(TelegramObject):
|
||||
|
||||
async def ban_member(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
revoke_messages: Optional[bool] = None,
|
||||
until_date: Optional[Union[int, datetime]] = None,
|
||||
*,
|
||||
@@ -877,7 +870,7 @@ class Chat(TelegramObject):
|
||||
|
||||
async def unban_member(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
only_if_banned: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -909,7 +902,7 @@ class Chat(TelegramObject):
|
||||
|
||||
async def promote_member(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
can_change_info: Optional[bool] = None,
|
||||
can_post_messages: Optional[bool] = None,
|
||||
can_edit_messages: Optional[bool] = None,
|
||||
@@ -922,6 +915,9 @@ class Chat(TelegramObject):
|
||||
can_manage_chat: Optional[bool] = None,
|
||||
can_manage_video_chats: Optional[bool] = None,
|
||||
can_manage_topics: Optional[bool] = None,
|
||||
can_post_stories: Optional[bool] = None,
|
||||
can_edit_stories: Optional[bool] = None,
|
||||
can_delete_stories: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -941,6 +937,9 @@ class Chat(TelegramObject):
|
||||
The argument ``can_manage_voice_chats`` was renamed to
|
||||
:paramref:`~telegram.Bot.promote_chat_member.can_manage_video_chats` in accordance to
|
||||
Bot API 6.0.
|
||||
.. versionchanged:: 20.6
|
||||
The arguments `can_post_stories`, `can_edit_stories` and `can_delete_stories` were
|
||||
added.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
@@ -966,11 +965,14 @@ class Chat(TelegramObject):
|
||||
can_manage_chat=can_manage_chat,
|
||||
can_manage_video_chats=can_manage_video_chats,
|
||||
can_manage_topics=can_manage_topics,
|
||||
can_post_stories=can_post_stories,
|
||||
can_edit_stories=can_edit_stories,
|
||||
can_delete_stories=can_delete_stories,
|
||||
)
|
||||
|
||||
async def restrict_member(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
permissions: ChatPermissions,
|
||||
until_date: Optional[Union[int, datetime]] = None,
|
||||
use_independent_chat_permissions: Optional[bool] = None,
|
||||
@@ -1086,7 +1088,7 @@ class Chat(TelegramObject):
|
||||
photo: FileInput,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1317,7 +1319,7 @@ class Chat(TelegramObject):
|
||||
text: str,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1372,7 +1374,7 @@ class Chat(TelegramObject):
|
||||
message_thread_id: Optional[int] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1448,7 +1450,7 @@ class Chat(TelegramObject):
|
||||
self,
|
||||
photo: Union[FileInput, "PhotoSize"],
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -1460,7 +1462,7 @@ class Chat(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1501,7 +1503,7 @@ class Chat(TelegramObject):
|
||||
phone_number: Optional[str] = None,
|
||||
first_name: Optional[str] = None,
|
||||
last_name: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
vcard: Optional[str] = None,
|
||||
@@ -1553,7 +1555,7 @@ class Chat(TelegramObject):
|
||||
performer: Optional[str] = None,
|
||||
title: Optional[str] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -1565,7 +1567,7 @@ class Chat(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1608,7 +1610,7 @@ class Chat(TelegramObject):
|
||||
self,
|
||||
document: Union[FileInput, "Document"],
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -1621,7 +1623,7 @@ class Chat(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1703,7 +1705,7 @@ class Chat(TelegramObject):
|
||||
async def send_game(
|
||||
self,
|
||||
game_short_name: str,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1760,7 +1762,7 @@ class Chat(TelegramObject):
|
||||
need_email: Optional[bool] = None,
|
||||
need_shipping_address: Optional[bool] = None,
|
||||
is_flexible: Optional[bool] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
provider_data: Optional[Union[str, object]] = None,
|
||||
@@ -1838,7 +1840,7 @@ class Chat(TelegramObject):
|
||||
self,
|
||||
latitude: Optional[float] = None,
|
||||
longitude: Optional[float] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
live_period: Optional[int] = None,
|
||||
@@ -1896,7 +1898,7 @@ class Chat(TelegramObject):
|
||||
height: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1908,7 +1910,7 @@ class Chat(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1951,7 +1953,7 @@ class Chat(TelegramObject):
|
||||
async def send_sticker(
|
||||
self,
|
||||
sticker: Union[FileInput, "Sticker"],
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1960,7 +1962,7 @@ class Chat(TelegramObject):
|
||||
emoji: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1999,7 +2001,7 @@ class Chat(TelegramObject):
|
||||
title: Optional[str] = None,
|
||||
address: Optional[str] = None,
|
||||
foursquare_id: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
foursquare_type: Optional[str] = None,
|
||||
@@ -2055,7 +2057,7 @@ class Chat(TelegramObject):
|
||||
video: Union[FileInput, "Video"],
|
||||
duration: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
width: Optional[int] = None,
|
||||
@@ -2071,7 +2073,7 @@ class Chat(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2117,7 +2119,7 @@ class Chat(TelegramObject):
|
||||
video_note: Union[FileInput, "VideoNote"],
|
||||
duration: Optional[int] = None,
|
||||
length: Optional[int] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2127,7 +2129,7 @@ class Chat(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2167,7 +2169,7 @@ class Chat(TelegramObject):
|
||||
voice: Union[FileInput, "Voice"],
|
||||
duration: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -2178,7 +2180,7 @@ class Chat(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2285,9 +2287,9 @@ class Chat(TelegramObject):
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
@@ -2335,9 +2337,9 @@ class Chat(TelegramObject):
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
@@ -2382,7 +2384,7 @@ class Chat(TelegramObject):
|
||||
self,
|
||||
from_chat_id: Union[str, int],
|
||||
message_id: int,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
*,
|
||||
@@ -2424,7 +2426,7 @@ class Chat(TelegramObject):
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
message_id: int,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
*,
|
||||
|
||||
@@ -31,26 +31,31 @@ class ChatAdministratorRights(TelegramObject):
|
||||
:attr:`can_delete_messages`, :attr:`can_manage_video_chats`, :attr:`can_restrict_members`,
|
||||
:attr:`can_promote_members`, :attr:`can_change_info`, :attr:`can_invite_users`,
|
||||
:attr:`can_post_messages`, :attr:`can_edit_messages`, :attr:`can_pin_messages`,
|
||||
:attr:`can_manage_topics` are equal.
|
||||
:attr:`can_manage_topics`, :attr:`can_post_stories`, :attr:`can_delete_stories`, and
|
||||
:attr:`can_edit_stories` are equal.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
:attr:`can_manage_topics` is considered as well when comparing objects of
|
||||
this type in terms of equality.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
.. versionchanged:: 20.6
|
||||
:attr:`can_post_stories`, :attr:`can_edit_stories`, and :attr:`can_delete_stories` are
|
||||
considered as well when comparing objects of this type in terms of equality.
|
||||
|
||||
Args:
|
||||
is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden.
|
||||
can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event
|
||||
log, chat statistics, message statistics in channels, see channel members, see
|
||||
anonymous administrators in supergroups and ignore slow mode. Implied by any other
|
||||
administrator privilege.
|
||||
log, chat statistics, boost list in channels, see channel members, report spam
|
||||
messages, see anonymous administrators in supergroups and ignore slow mode.
|
||||
Implied by any other administrator privilege.
|
||||
can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of
|
||||
other users.
|
||||
can_manage_video_chats (:obj:`bool`): :obj:`True`, if the administrator can manage video
|
||||
chats.
|
||||
can_restrict_members (:obj:`bool`): :obj:`True`, if the administrator can restrict, ban or
|
||||
unban chat members.
|
||||
unban chat members, or access supergroup statistics.
|
||||
can_promote_members (:obj:`bool`): :obj:`True`, if the administrator can add new
|
||||
administrators with a subset of their own privileges or demote administrators
|
||||
that they have promoted, directly or indirectly (promoted by administrators that
|
||||
@@ -60,11 +65,23 @@ class ChatAdministratorRights(TelegramObject):
|
||||
can_invite_users (:obj:`bool`): :obj:`True`, if the user is allowed to invite new users to
|
||||
the chat.
|
||||
can_post_messages (:obj:`bool`, optional): :obj:`True`, if the administrator can post
|
||||
messages in the channel; channels only.
|
||||
messages in the channel, or access channel statistics; channels only.
|
||||
can_edit_messages (:obj:`bool`, optional): :obj:`True`, if the administrator can edit
|
||||
messages of other users.
|
||||
can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin
|
||||
messages; groups and supergroups only.
|
||||
can_post_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can post
|
||||
stories in the channel; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_edit_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can edit
|
||||
stories posted by other users; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_delete_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can delete
|
||||
stories posted by other users; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed
|
||||
to create, rename, close, and reopen forum topics; supergroups only.
|
||||
|
||||
@@ -73,15 +90,15 @@ class ChatAdministratorRights(TelegramObject):
|
||||
Attributes:
|
||||
is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden.
|
||||
can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event
|
||||
log, chat statistics, message statistics in channels, see channel members, see
|
||||
anonymous administrators in supergroups and ignore slow mode. Implied by any other
|
||||
administrator privilege.
|
||||
log, chat statistics, boost list in channels, see channel members, report spam
|
||||
messages, see anonymous administrators in supergroups and ignore slow mode.
|
||||
Implied by any other administrator privilege.
|
||||
can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of
|
||||
other users.
|
||||
can_manage_video_chats (:obj:`bool`): :obj:`True`, if the administrator can manage video
|
||||
chats.
|
||||
can_restrict_members (:obj:`bool`): :obj:`True`, if the administrator can restrict, ban or
|
||||
unban chat members.
|
||||
unban chat members, or access supergroup statistics.
|
||||
can_promote_members (:obj:`bool`): :obj:`True`, if the administrator can add new
|
||||
administrators with a subset of their own privileges or demote administrators that he
|
||||
has promoted, directly or indirectly (promoted by administrators that were appointed by
|
||||
@@ -91,11 +108,23 @@ class ChatAdministratorRights(TelegramObject):
|
||||
can_invite_users (:obj:`bool`): :obj:`True`, if the user is allowed to invite new users to
|
||||
the chat.
|
||||
can_post_messages (:obj:`bool`): Optional. :obj:`True`, if the administrator can post
|
||||
messages in the channel; channels only.
|
||||
messages in the channel, or access channel statistics; channels only.
|
||||
can_edit_messages (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit
|
||||
messages of other users.
|
||||
can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin
|
||||
messages; groups and supergroups only.
|
||||
can_post_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can post
|
||||
stories in the channel; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_edit_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit
|
||||
stories posted by other users; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_delete_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can delete
|
||||
stories posted by other users; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
|
||||
to create, rename, close, and reopen forum topics; supergroups only.
|
||||
|
||||
@@ -115,6 +144,9 @@ class ChatAdministratorRights(TelegramObject):
|
||||
"can_edit_messages",
|
||||
"can_pin_messages",
|
||||
"can_manage_topics",
|
||||
"can_post_stories",
|
||||
"can_edit_stories",
|
||||
"can_delete_stories",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@@ -131,6 +163,9 @@ class ChatAdministratorRights(TelegramObject):
|
||||
can_edit_messages: Optional[bool] = None,
|
||||
can_pin_messages: Optional[bool] = None,
|
||||
can_manage_topics: Optional[bool] = None,
|
||||
can_post_stories: Optional[bool] = None,
|
||||
can_edit_stories: Optional[bool] = None,
|
||||
can_delete_stories: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> None:
|
||||
@@ -148,6 +183,9 @@ class ChatAdministratorRights(TelegramObject):
|
||||
self.can_post_messages: Optional[bool] = can_post_messages
|
||||
self.can_edit_messages: Optional[bool] = can_edit_messages
|
||||
self.can_pin_messages: Optional[bool] = can_pin_messages
|
||||
self.can_post_stories: Optional[bool] = can_post_stories
|
||||
self.can_edit_stories: Optional[bool] = can_edit_stories
|
||||
self.can_delete_stories: Optional[bool] = can_delete_stories
|
||||
self.can_manage_topics: Optional[bool] = can_manage_topics
|
||||
|
||||
self._id_attrs = (
|
||||
@@ -163,6 +201,9 @@ class ChatAdministratorRights(TelegramObject):
|
||||
self.can_edit_messages,
|
||||
self.can_pin_messages,
|
||||
self.can_manage_topics,
|
||||
self.can_post_stories,
|
||||
self.can_edit_stories,
|
||||
self.can_delete_stories,
|
||||
)
|
||||
|
||||
self._freeze()
|
||||
@@ -176,7 +217,7 @@ class ChatAdministratorRights(TelegramObject):
|
||||
|
||||
.. versionadded:: 20.0
|
||||
"""
|
||||
return cls(True, True, True, True, True, True, True, True, True, True, True, True)
|
||||
return cls(*(True,) * len(cls.__slots__))
|
||||
|
||||
@classmethod
|
||||
def no_rights(cls) -> "ChatAdministratorRights":
|
||||
@@ -186,6 +227,4 @@ class ChatAdministratorRights(TelegramObject):
|
||||
|
||||
.. versionadded:: 20.0
|
||||
"""
|
||||
return cls(
|
||||
False, False, False, False, False, False, False, False, False, False, False, False
|
||||
)
|
||||
return cls(*(False,) * len(cls.__slots__))
|
||||
|
||||
@@ -63,7 +63,7 @@ class ChatJoinRequest(TelegramObject):
|
||||
request. This number may have more than 32 significant bits and some programming
|
||||
languages may have difficulty/silent defects in interpreting it. But it has at most 52
|
||||
significant bits, so a 64-bit integer or double-precision float type are safe for
|
||||
storing this identifier. The bot can use this identifier for 24 hours to send messages
|
||||
storing this identifier. The bot can use this identifier for 5 minutes to send messages
|
||||
until the join request is processed, assuming no other administrator contacted the
|
||||
user.
|
||||
|
||||
|
||||
+42
-7
@@ -218,12 +218,25 @@ class ChatMemberAdministrator(ChatMember):
|
||||
can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite
|
||||
new users to the chat.
|
||||
can_post_messages (:obj:`bool`, optional): :obj:`True`, if the
|
||||
administrator can post in the channel, channels only.
|
||||
administrator can post messages in the channel, or access channel statistics; channels
|
||||
only.
|
||||
can_edit_messages (:obj:`bool`, optional): :obj:`True`, if the
|
||||
administrator can edit messages of other users and can pin
|
||||
messages; channels only.
|
||||
can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed
|
||||
to pin messages; groups and supergroups only.
|
||||
can_post_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can post
|
||||
stories in the channel; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_edit_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can edit
|
||||
stories posted by other users; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_delete_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can delete
|
||||
stories posted by other users; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed
|
||||
to create, rename, close, and reopen forum topics; supergroups only.
|
||||
|
||||
@@ -238,10 +251,10 @@ class ChatMemberAdministrator(ChatMember):
|
||||
is allowed to edit administrator privileges of that user.
|
||||
is_anonymous (:obj:`bool`): :obj:`True`, if the user's
|
||||
presence in the chat is hidden.
|
||||
can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator
|
||||
can access the chat event log, chat statistics, message statistics in
|
||||
channels, see channel members, see anonymous administrators in supergroups
|
||||
and ignore slow mode. Implied by any other administrator privilege.
|
||||
can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event
|
||||
log, chat statistics, boost list in channels, see channel members, report spam
|
||||
messages, see anonymous administrators in supergroups and ignore slow mode.
|
||||
Implied by any other administrator privilege.
|
||||
can_delete_messages (:obj:`bool`): :obj:`True`, if the
|
||||
administrator can delete messages of other users.
|
||||
can_manage_video_chats (:obj:`bool`): :obj:`True`, if the
|
||||
@@ -249,7 +262,7 @@ class ChatMemberAdministrator(ChatMember):
|
||||
|
||||
.. versionadded:: 20.0
|
||||
can_restrict_members (:obj:`bool`): :obj:`True`, if the
|
||||
administrator can restrict, ban or unban chat members.
|
||||
administrator can restrict, ban or unban chat members, or access supergroup statistics.
|
||||
can_promote_members (:obj:`bool`): :obj:`True`, if the administrator can add new
|
||||
administrators with a subset of their own privileges or demote administrators
|
||||
that they have promoted, directly or indirectly (promoted by administrators that
|
||||
@@ -259,12 +272,25 @@ class ChatMemberAdministrator(ChatMember):
|
||||
can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite
|
||||
new users to the chat.
|
||||
can_post_messages (:obj:`bool`): Optional. :obj:`True`, if the
|
||||
administrator can post in the channel, channels only.
|
||||
administrator can post messages in the channel or access channel statistics;
|
||||
channels only.
|
||||
can_edit_messages (:obj:`bool`): Optional. :obj:`True`, if the
|
||||
administrator can edit messages of other users and can pin
|
||||
messages; channels only.
|
||||
can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
|
||||
to pin messages; groups and supergroups only.
|
||||
can_post_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can post
|
||||
stories in the channel; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_edit_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit
|
||||
stories posted by other users; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_delete_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can delete
|
||||
stories posted by other users; channels only.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
|
||||
to create, rename, close, and reopen forum topics; supergroups only
|
||||
|
||||
@@ -287,6 +313,9 @@ class ChatMemberAdministrator(ChatMember):
|
||||
"can_pin_messages",
|
||||
"can_manage_topics",
|
||||
"custom_title",
|
||||
"can_post_stories",
|
||||
"can_edit_stories",
|
||||
"can_delete_stories",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@@ -306,6 +335,9 @@ class ChatMemberAdministrator(ChatMember):
|
||||
can_pin_messages: Optional[bool] = None,
|
||||
can_manage_topics: Optional[bool] = None,
|
||||
custom_title: Optional[str] = None,
|
||||
can_post_stories: Optional[bool] = None,
|
||||
can_edit_stories: Optional[bool] = None,
|
||||
can_delete_stories: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -325,6 +357,9 @@ class ChatMemberAdministrator(ChatMember):
|
||||
self.can_pin_messages: Optional[bool] = can_pin_messages
|
||||
self.can_manage_topics: Optional[bool] = can_manage_topics
|
||||
self.custom_title: Optional[str] = custom_title
|
||||
self.can_post_stories: Optional[bool] = can_post_stories
|
||||
self.can_edit_stories: Optional[bool] = can_edit_stories
|
||||
self.can_delete_stories: Optional[bool] = can_delete_stories
|
||||
|
||||
|
||||
class ChatMemberMember(ChatMember):
|
||||
|
||||
@@ -111,7 +111,7 @@ class InlineQuery(TelegramObject):
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Required
|
||||
self.id: str = id # pylint: disable=invalid-name
|
||||
self.id: str = id
|
||||
self.from_user: User = from_user
|
||||
self.query: str = query
|
||||
self.offset: str = offset
|
||||
|
||||
@@ -60,7 +60,7 @@ class InlineQueryResult(TelegramObject):
|
||||
|
||||
# Required
|
||||
self.type: str = type
|
||||
self.id: str = str(id) # pylint: disable=invalid-name
|
||||
self.id: str = str(id)
|
||||
|
||||
self._id_attrs = (self.id,)
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class InlineQueryResultsButton(TelegramObject):
|
||||
`Web App <https://core.telegram.org/bots/webapps>`_ that will be launched when the
|
||||
user presses the button. The Web App will be able to switch back to the inline mode
|
||||
using the method
|
||||
`switchInlineQuery <https://core.telegram.org/bots/webapps#initializing-web-apps>`_
|
||||
`switchInlineQuery <https://core.telegram.org/bots/webapps#initializing-mini-apps>`_
|
||||
inside the Web App.
|
||||
start_parameter (:obj:`str`, optional): Deep-linking parameter for the
|
||||
:guilabel:`/start` message sent to the bot when user presses the switch button.
|
||||
|
||||
@@ -86,7 +86,7 @@ class LoginUrl(TelegramObject):
|
||||
def __init__(
|
||||
self,
|
||||
url: str,
|
||||
forward_text: Optional[bool] = None,
|
||||
forward_text: Optional[str] = None,
|
||||
bot_username: Optional[str] = None,
|
||||
request_write_access: Optional[bool] = None,
|
||||
*,
|
||||
@@ -96,7 +96,7 @@ class LoginUrl(TelegramObject):
|
||||
# Required
|
||||
self.url: str = url
|
||||
# Optional
|
||||
self.forward_text: Optional[bool] = forward_text
|
||||
self.forward_text: Optional[str] = forward_text
|
||||
self.bot_username: Optional[str] = bot_username
|
||||
self.request_write_access: Optional[bool] = request_write_access
|
||||
|
||||
|
||||
@@ -55,7 +55,10 @@ class MenuButton(TelegramObject):
|
||||
__slots__ = ("type",)
|
||||
|
||||
def __init__(
|
||||
self, type: str, *, api_kwargs: Optional[JSONDict] = None # skipcq: PYL-W0622
|
||||
self,
|
||||
type: str, # skipcq: PYL-W0622
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
): # pylint: disable=redefined-builtin
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.type: str = type
|
||||
|
||||
+44
-42
@@ -61,7 +61,6 @@ from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestam
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
|
||||
from telegram._utils.types import (
|
||||
CorrectOptionID,
|
||||
DVInput,
|
||||
FileInput,
|
||||
JSONDict,
|
||||
MarkdownVersion,
|
||||
@@ -330,7 +329,10 @@ class Message(TelegramObject):
|
||||
|
||||
.. versionadded:: 20.0
|
||||
write_access_allowed (:class:`telegram.WriteAccessAllowed`, optional): Service message:
|
||||
the user allowed the bot added to the attachment menu to write messages.
|
||||
the user allowed the bot to write messages after adding it to the attachment or side
|
||||
menu, launching a Web App from a link, or accepting an explicit request from a Web App
|
||||
sent by the method
|
||||
`requestWriteAccess <https://core.telegram.org/bots/webapps#initializing-mini-apps>`_.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
has_media_spoiler (:obj:`bool`, optional): :obj:`True`, if the message media is covered
|
||||
@@ -854,7 +856,7 @@ class Message(TelegramObject):
|
||||
return self.chat.id
|
||||
|
||||
@property
|
||||
def id(self) -> int: # pylint: disable=invalid-name
|
||||
def id(self) -> int:
|
||||
"""
|
||||
:obj:`int`: Shortcut for :attr:`message_id`.
|
||||
|
||||
@@ -1058,7 +1060,7 @@ class Message(TelegramObject):
|
||||
text: str,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1112,7 +1114,7 @@ class Message(TelegramObject):
|
||||
self,
|
||||
text: str,
|
||||
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1176,7 +1178,7 @@ class Message(TelegramObject):
|
||||
self,
|
||||
text: str,
|
||||
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1236,7 +1238,7 @@ class Message(TelegramObject):
|
||||
self,
|
||||
text: str,
|
||||
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1305,7 +1307,7 @@ class Message(TelegramObject):
|
||||
*,
|
||||
quote: Optional[bool] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1354,7 +1356,7 @@ class Message(TelegramObject):
|
||||
self,
|
||||
photo: Union[FileInput, "PhotoSize"],
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -1367,7 +1369,7 @@ class Message(TelegramObject):
|
||||
filename: Optional[str] = None,
|
||||
quote: Optional[bool] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1416,7 +1418,7 @@ class Message(TelegramObject):
|
||||
performer: Optional[str] = None,
|
||||
title: Optional[str] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -1429,7 +1431,7 @@ class Message(TelegramObject):
|
||||
filename: Optional[str] = None,
|
||||
quote: Optional[bool] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1478,7 +1480,7 @@ class Message(TelegramObject):
|
||||
self,
|
||||
document: Union[FileInput, "Document"],
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -1492,7 +1494,7 @@ class Message(TelegramObject):
|
||||
filename: Optional[str] = None,
|
||||
quote: Optional[bool] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1543,7 +1545,7 @@ class Message(TelegramObject):
|
||||
height: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1556,7 +1558,7 @@ class Message(TelegramObject):
|
||||
filename: Optional[str] = None,
|
||||
quote: Optional[bool] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1606,7 +1608,7 @@ class Message(TelegramObject):
|
||||
async def reply_sticker(
|
||||
self,
|
||||
sticker: Union[FileInput, "Sticker"],
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1616,7 +1618,7 @@ class Message(TelegramObject):
|
||||
*,
|
||||
quote: Optional[bool] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1659,7 +1661,7 @@ class Message(TelegramObject):
|
||||
video: Union[FileInput, "Video"],
|
||||
duration: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
width: Optional[int] = None,
|
||||
@@ -1676,7 +1678,7 @@ class Message(TelegramObject):
|
||||
filename: Optional[str] = None,
|
||||
quote: Optional[bool] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1728,7 +1730,7 @@ class Message(TelegramObject):
|
||||
video_note: Union[FileInput, "VideoNote"],
|
||||
duration: Optional[int] = None,
|
||||
length: Optional[int] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1739,7 +1741,7 @@ class Message(TelegramObject):
|
||||
filename: Optional[str] = None,
|
||||
quote: Optional[bool] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1786,7 +1788,7 @@ class Message(TelegramObject):
|
||||
voice: Union[FileInput, "Voice"],
|
||||
duration: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -1798,7 +1800,7 @@ class Message(TelegramObject):
|
||||
filename: Optional[str] = None,
|
||||
quote: Optional[bool] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1845,7 +1847,7 @@ class Message(TelegramObject):
|
||||
self,
|
||||
latitude: Optional[float] = None,
|
||||
longitude: Optional[float] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
live_period: Optional[int] = None,
|
||||
@@ -1909,7 +1911,7 @@ class Message(TelegramObject):
|
||||
title: Optional[str] = None,
|
||||
address: Optional[str] = None,
|
||||
foursquare_id: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
foursquare_type: Optional[str] = None,
|
||||
@@ -1972,7 +1974,7 @@ class Message(TelegramObject):
|
||||
phone_number: Optional[str] = None,
|
||||
first_name: Optional[str] = None,
|
||||
last_name: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
vcard: Optional[str] = None,
|
||||
@@ -2181,7 +2183,7 @@ class Message(TelegramObject):
|
||||
async def reply_game(
|
||||
self,
|
||||
game_short_name: str,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2247,7 +2249,7 @@ class Message(TelegramObject):
|
||||
need_email: Optional[bool] = None,
|
||||
need_shipping_address: Optional[bool] = None,
|
||||
is_flexible: Optional[bool] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
provider_data: Optional[Union[str, object]] = None,
|
||||
@@ -2333,7 +2335,7 @@ class Message(TelegramObject):
|
||||
async def forward(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
*,
|
||||
@@ -2386,9 +2388,9 @@ class Message(TelegramObject):
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
@@ -2442,9 +2444,9 @@ class Message(TelegramObject):
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
@@ -2504,7 +2506,7 @@ class Message(TelegramObject):
|
||||
text: str,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2550,7 +2552,7 @@ class Message(TelegramObject):
|
||||
async def edit_caption(
|
||||
self,
|
||||
caption: Optional[str] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
*,
|
||||
@@ -2597,7 +2599,7 @@ class Message(TelegramObject):
|
||||
async def edit_media(
|
||||
self,
|
||||
media: "InputMedia",
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2681,7 +2683,7 @@ class Message(TelegramObject):
|
||||
self,
|
||||
latitude: Optional[float] = None,
|
||||
longitude: Optional[float] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
horizontal_accuracy: Optional[float] = None,
|
||||
heading: Optional[int] = None,
|
||||
proximity_alert_radius: Optional[int] = None,
|
||||
@@ -2731,7 +2733,7 @@ class Message(TelegramObject):
|
||||
|
||||
async def stop_live_location(
|
||||
self,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2771,7 +2773,7 @@ class Message(TelegramObject):
|
||||
|
||||
async def set_game_score(
|
||||
self,
|
||||
user_id: Union[int, str],
|
||||
user_id: int,
|
||||
score: int,
|
||||
force: Optional[bool] = None,
|
||||
disable_edit_message: Optional[bool] = None,
|
||||
@@ -2816,7 +2818,7 @@ class Message(TelegramObject):
|
||||
|
||||
async def get_game_high_scores(
|
||||
self,
|
||||
user_id: Union[int, str],
|
||||
user_id: int,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2886,7 +2888,7 @@ class Message(TelegramObject):
|
||||
|
||||
async def stop_poll(
|
||||
self,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
||||
@@ -471,7 +471,11 @@ class _CredentialsBase(TelegramObject):
|
||||
__slots__ = ("hash", "secret", "file_hash", "data_hash")
|
||||
|
||||
def __init__(
|
||||
self, hash: str, secret: str, *, api_kwargs: Optional[JSONDict] = None # skipcq: PYL-W0622
|
||||
self,
|
||||
hash: str, # skipcq: PYL-W0622
|
||||
secret: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram EncryptedPassportElement."""
|
||||
from base64 import b64decode
|
||||
from typing import TYPE_CHECKING, Optional, Sequence, Tuple
|
||||
from typing import TYPE_CHECKING, Optional, Sequence, Tuple, Union
|
||||
|
||||
from telegram._passport.credentials import decrypt_json
|
||||
from telegram._passport.data import IdDocumentData, PersonalDetails, ResidentialAddress
|
||||
@@ -54,7 +54,7 @@ class EncryptedPassportElement(TelegramObject):
|
||||
data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocumentData` | \
|
||||
:class:`telegram.ResidentialAddress` | :obj:`str`, optional):
|
||||
Decrypted or encrypted data, available for "personal_details", "passport",
|
||||
"driver_license", "identity_card", "identity_passport" and "address" types.
|
||||
"driver_license", "identity_card", "internal_passport" and "address" types.
|
||||
phone_number (:obj:`str`, optional): User's verified phone number, available only for
|
||||
"phone_number" type.
|
||||
email (:obj:`str`, optional): User's verified email address, available only for "email"
|
||||
@@ -96,7 +96,7 @@ class EncryptedPassportElement(TelegramObject):
|
||||
data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocumentData` | \
|
||||
:class:`telegram.ResidentialAddress` | :obj:`str`):
|
||||
Optional. Decrypted or encrypted data, available for "personal_details", "passport",
|
||||
"driver_license", "identity_card", "identity_passport" and "address" types.
|
||||
"driver_license", "identity_card", "internal_passport" and "address" types.
|
||||
phone_number (:obj:`str`): Optional. User's verified phone number, available only for
|
||||
"phone_number" type.
|
||||
email (:obj:`str`): Optional. User's verified email address, available only for "email"
|
||||
@@ -151,7 +151,7 @@ class EncryptedPassportElement(TelegramObject):
|
||||
self,
|
||||
type: str, # pylint: disable=redefined-builtin
|
||||
hash: str, # pylint: disable=redefined-builtin
|
||||
data: Optional[PersonalDetails] = None,
|
||||
data: Optional[Union[PersonalDetails, IdDocumentData, ResidentialAddress]] = None,
|
||||
phone_number: Optional[str] = None,
|
||||
email: Optional[str] = None,
|
||||
files: Optional[Sequence[PassportFile]] = None,
|
||||
@@ -168,7 +168,7 @@ class EncryptedPassportElement(TelegramObject):
|
||||
# Required
|
||||
self.type: str = type
|
||||
# Optionals
|
||||
self.data: Optional[PersonalDetails] = data
|
||||
self.data: Optional[Union[PersonalDetails, IdDocumentData, ResidentialAddress]] = data
|
||||
self.phone_number: Optional[str] = phone_number
|
||||
self.email: Optional[str] = email
|
||||
self.files: Tuple[PassportFile, ...] = parse_sequence_arg(files)
|
||||
|
||||
@@ -19,10 +19,12 @@
|
||||
# pylint: disable=redefined-builtin
|
||||
"""This module contains the classes that represent Telegram PassportElementError."""
|
||||
|
||||
from typing import Optional
|
||||
from typing import List, Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
|
||||
class PassportElementError(TelegramObject):
|
||||
@@ -173,23 +175,48 @@ class PassportElementErrorFiles(PassportElementError):
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``,
|
||||
``"passport_registration"``, ``"temporary_registration"``.
|
||||
file_hashes (List[:obj:`str`]): List of base64-encoded file hashes.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("file_hashes",)
|
||||
__slots__ = ("_file_hashes",)
|
||||
|
||||
def __init__(
|
||||
self, type: str, file_hashes: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
||||
self,
|
||||
type: str,
|
||||
file_hashes: List[str],
|
||||
message: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
# Required
|
||||
super().__init__("files", type, message, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.file_hashes: str = file_hashes
|
||||
self._file_hashes: List[str] = file_hashes
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.message, *tuple(file_hashes))
|
||||
|
||||
def to_dict(self, recursive: bool = True) -> JSONDict:
|
||||
"""See :meth:`telegram.TelegramObject.to_dict` for details."""
|
||||
data = super().to_dict(recursive)
|
||||
data["file_hashes"] = self._file_hashes
|
||||
return data
|
||||
|
||||
@property
|
||||
def file_hashes(self) -> List[str]:
|
||||
"""List of base64-encoded file hashes.
|
||||
|
||||
.. deprecated:: 20.6
|
||||
This attribute will return a tuple instead of a list in future major versions.
|
||||
"""
|
||||
warn(
|
||||
"The attribute `file_hashes` will return a tuple instead of a list in future major"
|
||||
" versions.",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._file_hashes
|
||||
|
||||
|
||||
class PassportElementErrorFrontSide(PassportElementError):
|
||||
"""
|
||||
@@ -365,23 +392,49 @@ class PassportElementErrorTranslationFiles(PassportElementError):
|
||||
one of ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
||||
``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``,
|
||||
``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``.
|
||||
file_hashes (List[:obj:`str`]): List of base64-encoded file hashes.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("file_hashes",)
|
||||
__slots__ = ("_file_hashes",)
|
||||
|
||||
def __init__(
|
||||
self, type: str, file_hashes: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
||||
self,
|
||||
type: str,
|
||||
file_hashes: List[str],
|
||||
message: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
# Required
|
||||
super().__init__("translation_files", type, message, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.file_hashes: str = file_hashes
|
||||
self._file_hashes: List[str] = file_hashes
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.message, *tuple(file_hashes))
|
||||
|
||||
def to_dict(self, recursive: bool = True) -> JSONDict:
|
||||
"""See :meth:`telegram.TelegramObject.to_dict` for details."""
|
||||
data = super().to_dict(recursive)
|
||||
data["file_hashes"] = self._file_hashes
|
||||
return data
|
||||
|
||||
@property
|
||||
def file_hashes(self) -> List[str]:
|
||||
"""List of base64-encoded file hashes.
|
||||
|
||||
.. deprecated:: 20.6
|
||||
This attribute will return a tuple instead of a list in future major versions.
|
||||
"""
|
||||
warn(
|
||||
"The attribute `file_hashes` will return a tuple instead of a list in future major"
|
||||
" versions. See the stability policy:"
|
||||
" https://docs.python-telegram-bot.org/en/stable/stability_policy.html",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._file_hashes
|
||||
|
||||
|
||||
class PassportElementErrorUnspecified(PassportElementError):
|
||||
"""
|
||||
|
||||
@@ -23,6 +23,8 @@ from typing import TYPE_CHECKING, List, Optional, Tuple
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import JSONDict, ODVInput
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File, FileCredentials
|
||||
@@ -45,6 +47,10 @@ class PassportFile(TelegramObject):
|
||||
file_size (:obj:`int`): File size in bytes.
|
||||
file_date (:obj:`int`): Unix time when the file was uploaded.
|
||||
|
||||
.. deprecated:: 20.6
|
||||
This argument will only accept a datetime instead of an integer in future
|
||||
major versions.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
@@ -52,13 +58,10 @@ class PassportFile(TelegramObject):
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
file_size (:obj:`int`): File size in bytes.
|
||||
file_date (:obj:`int`): Unix time when the file was uploaded.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"file_date",
|
||||
"_file_date",
|
||||
"file_id",
|
||||
"file_size",
|
||||
"_credentials",
|
||||
@@ -81,7 +84,7 @@ class PassportFile(TelegramObject):
|
||||
self.file_id: str = file_id
|
||||
self.file_unique_id: str = file_unique_id
|
||||
self.file_size: int = file_size
|
||||
self.file_date: int = file_date
|
||||
self._file_date: int = file_date
|
||||
# Optionals
|
||||
|
||||
self._credentials: Optional[FileCredentials] = credentials
|
||||
@@ -90,6 +93,27 @@ class PassportFile(TelegramObject):
|
||||
|
||||
self._freeze()
|
||||
|
||||
def to_dict(self, recursive: bool = True) -> JSONDict:
|
||||
"""See :meth:`telegram.TelegramObject.to_dict` for details."""
|
||||
data = super().to_dict(recursive)
|
||||
data["file_date"] = self._file_date
|
||||
return data
|
||||
|
||||
@property
|
||||
def file_date(self) -> int:
|
||||
""":obj:`int`: Unix time when the file was uploaded.
|
||||
|
||||
.. deprecated:: 20.6
|
||||
This attribute will return a datetime instead of a integer in future major versions.
|
||||
"""
|
||||
warn(
|
||||
"The attribute `file_date` will return a datetime instead of an integer in future"
|
||||
" major versions.",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._file_date
|
||||
|
||||
@classmethod
|
||||
def de_json_decrypted(
|
||||
cls, data: Optional[JSONDict], bot: "Bot", credentials: "FileCredentials"
|
||||
|
||||
@@ -56,7 +56,7 @@ class OrderInfo(TelegramObject):
|
||||
name: Optional[str] = None,
|
||||
phone_number: Optional[str] = None,
|
||||
email: Optional[str] = None,
|
||||
shipping_address: Optional[str] = None,
|
||||
shipping_address: Optional[ShippingAddress] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -64,7 +64,7 @@ class OrderInfo(TelegramObject):
|
||||
self.name: Optional[str] = name
|
||||
self.phone_number: Optional[str] = phone_number
|
||||
self.email: Optional[str] = email
|
||||
self.shipping_address: Optional[str] = shipping_address
|
||||
self.shipping_address: Optional[ShippingAddress] = shipping_address
|
||||
|
||||
self._id_attrs = (self.name, self.phone_number, self.email, self.shipping_address)
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ class PreCheckoutQuery(TelegramObject):
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.id: str = id # pylint: disable=invalid-name
|
||||
self.id: str = id
|
||||
self.from_user: User = from_user
|
||||
self.currency: str = currency
|
||||
self.total_amount: int = total_amount
|
||||
@@ -120,7 +120,7 @@ class PreCheckoutQuery(TelegramObject):
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
async def answer( # pylint: disable=invalid-name
|
||||
async def answer(
|
||||
self,
|
||||
ok: bool,
|
||||
error_message: Optional[str] = None,
|
||||
|
||||
@@ -66,7 +66,7 @@ class ShippingOption(TelegramObject):
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
self.id: str = id # pylint: disable=invalid-name
|
||||
self.id: str = id
|
||||
self.title: str = title
|
||||
self.prices: Tuple[LabeledPrice, ...] = parse_sequence_arg(prices)
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
from typing import TYPE_CHECKING, Optional, Sequence
|
||||
|
||||
from telegram._payment.shippingaddress import ShippingAddress
|
||||
from telegram._payment.shippingoption import ShippingOption
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
@@ -29,6 +28,7 @@ from telegram._utils.types import JSONDict, ODVInput
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
from telegram._payment.shippingoption import ShippingOption
|
||||
|
||||
|
||||
class ShippingQuery(TelegramObject):
|
||||
@@ -67,7 +67,7 @@ class ShippingQuery(TelegramObject):
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.id: str = id # pylint: disable=invalid-name
|
||||
self.id: str = id
|
||||
self.from_user: User = from_user
|
||||
self.invoice_payload: str = invoice_payload
|
||||
self.shipping_address: ShippingAddress = shipping_address
|
||||
@@ -89,10 +89,10 @@ class ShippingQuery(TelegramObject):
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
async def answer( # pylint: disable=invalid-name
|
||||
async def answer(
|
||||
self,
|
||||
ok: bool,
|
||||
shipping_options: Optional[Sequence[ShippingOption]] = None,
|
||||
shipping_options: Optional[Sequence["ShippingOption"]] = None,
|
||||
error_message: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
||||
+8
-21
@@ -29,8 +29,6 @@ from telegram._utils import enum
|
||||
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
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
@@ -89,9 +87,11 @@ class PollAnswer(TelegramObject):
|
||||
|
||||
.. versionchanged:: 20.5
|
||||
The order of :paramref:`option_ids` and :paramref:`user` is changed in
|
||||
20.5 as the latter one became optional. We currently provide
|
||||
backward compatibility for this but it will be removed in the future.
|
||||
Please update your code to use the new order.
|
||||
20.5 as the latter one became optional.
|
||||
|
||||
.. versionchanged:: 20.6
|
||||
Backward compatiblity for changed order of :paramref:`option_ids` and :paramref:`user`
|
||||
was removed.
|
||||
|
||||
Args:
|
||||
poll_id (:obj:`str`): Unique poll identifier.
|
||||
@@ -145,21 +145,8 @@ class PollAnswer(TelegramObject):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.poll_id: str = poll_id
|
||||
self.voter_chat: Optional[Chat] = voter_chat
|
||||
|
||||
if isinstance(option_ids, User) or isinstance(user, tuple):
|
||||
warn(
|
||||
"From v20.5 the order of `option_ids` and `user` is changed as the latter one"
|
||||
" became optional. Please update your code to use the new order.",
|
||||
category=PTBDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
self.option_ids: Tuple[int, ...] = parse_sequence_arg(user)
|
||||
self.user: Optional[User] = option_ids
|
||||
else:
|
||||
self.option_ids: Tuple[int, ...] = parse_sequence_arg( # type: ignore[no-redef]
|
||||
option_ids
|
||||
)
|
||||
self.user: Optional[User] = user # type: ignore[no-redef]
|
||||
self.option_ids: Tuple[int, ...] = parse_sequence_arg(option_ids)
|
||||
self.user: Optional[User] = user
|
||||
|
||||
self._id_attrs = (
|
||||
self.poll_id,
|
||||
@@ -302,7 +289,7 @@ class Poll(TelegramObject):
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.id: str = id # pylint: disable=invalid-name
|
||||
self.id: str = id
|
||||
self.question: str = question
|
||||
self.options: Tuple[PollOption, ...] = parse_sequence_arg(options)
|
||||
self.total_voter_count: int = total_voter_count
|
||||
|
||||
+156
-156
@@ -110,43 +110,53 @@ class TelegramObject:
|
||||
# We don't do anything with api_kwargs here - see docstring of _apply_api_kwargs
|
||||
self.api_kwargs: Mapping[str, Any] = MappingProxyType(api_kwargs or {})
|
||||
|
||||
def _freeze(self) -> None:
|
||||
self._frozen = True
|
||||
def __eq__(self, other: object) -> bool:
|
||||
"""Compares this object with :paramref:`other` in terms of equality.
|
||||
If this object and :paramref:`other` are `not` objects of the same class,
|
||||
this comparison will fall back to Python's default implementation of :meth:`object.__eq__`.
|
||||
Otherwise, both objects may be compared in terms of equality, if the corresponding
|
||||
subclass of :class:`TelegramObject` has defined a set of attributes to compare and
|
||||
the objects are considered to be equal, if all of these attributes are equal.
|
||||
If the subclass has not defined a set of attributes to compare, a warning will be issued.
|
||||
|
||||
def _unfreeze(self) -> None:
|
||||
self._frozen = False
|
||||
Tip:
|
||||
If instances of a class in the :mod:`telegram` module are comparable in terms of
|
||||
equality, the documentation of the class will state the attributes that will be used
|
||||
for this comparison.
|
||||
|
||||
@contextmanager
|
||||
def _unfrozen(self: Tele_co) -> Iterator[Tele_co]:
|
||||
"""Context manager to temporarily unfreeze the object. For internal use only.
|
||||
Args:
|
||||
other (:obj:`object`): The object to compare with.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
Note:
|
||||
with to._unfrozen() as other_to:
|
||||
assert to is other_to
|
||||
"""
|
||||
self._unfreeze()
|
||||
yield self
|
||||
self._freeze()
|
||||
if isinstance(other, self.__class__):
|
||||
if not self._id_attrs:
|
||||
warn(
|
||||
f"Objects of type {self.__class__.__name__} can not be meaningfully tested for"
|
||||
" equivalence.",
|
||||
stacklevel=2,
|
||||
)
|
||||
if not other._id_attrs:
|
||||
warn(
|
||||
f"Objects of type {other.__class__.__name__} can not be meaningfully tested"
|
||||
" for equivalence.",
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._id_attrs == other._id_attrs
|
||||
return super().__eq__(other)
|
||||
|
||||
def _apply_api_kwargs(self, api_kwargs: JSONDict) -> None:
|
||||
"""Loops through the api kwargs and for every key that exists as attribute of the
|
||||
object (and is None), it moves the value from `api_kwargs` to the attribute.
|
||||
*Edits `api_kwargs` in place!*
|
||||
def __hash__(self) -> int:
|
||||
"""Builds a hash value for this object such that the hash of two objects is equal if and
|
||||
only if the objects are equal in terms of :meth:`__eq__`.
|
||||
|
||||
This method is currently only called in the unpickling process, i.e. not on "normal" init.
|
||||
This is because
|
||||
* automating this is tricky to get right: It should be called at the *end* of the __init__,
|
||||
preferably only once at the end of the __init__ of the last child class. This could be
|
||||
done via __init_subclass__, but it's hard to not destroy the signature of __init__ in the
|
||||
process.
|
||||
* calling it manually in every __init__ is tedious
|
||||
* There probably is no use case for it anyway. If you manually initialize a TO subclass,
|
||||
then you can pass everything as proper argument.
|
||||
Returns:
|
||||
:obj:`int`
|
||||
"""
|
||||
# we convert to list to ensure that the list doesn't change length while we loop
|
||||
for key in list(api_kwargs.keys()):
|
||||
if getattr(self, key, True) is None:
|
||||
setattr(self, key, api_kwargs.pop(key))
|
||||
if self._id_attrs:
|
||||
return hash((self.__class__, self._id_attrs))
|
||||
return super().__hash__()
|
||||
|
||||
def __setattr__(self, key: str, value: object) -> None:
|
||||
"""Overrides :meth:`object.__setattr__` to prevent the overriding of attributes.
|
||||
@@ -364,6 +374,122 @@ class TelegramObject:
|
||||
self.set_bot(bot)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def _parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]:
|
||||
"""Should be called by subclasses that override de_json to ensure that the input
|
||||
is not altered. Whoever calls de_json might still want to use the original input
|
||||
for something else.
|
||||
"""
|
||||
return None if data is None else data.copy()
|
||||
|
||||
@classmethod
|
||||
def _de_json(
|
||||
cls: Type[Tele_co],
|
||||
data: Optional[JSONDict],
|
||||
bot: "Bot",
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> Optional[Tele_co]:
|
||||
if data is None:
|
||||
return None
|
||||
|
||||
# try-except is significantly faster in case we already have a correct argument set
|
||||
try:
|
||||
obj = cls(**data, api_kwargs=api_kwargs)
|
||||
except TypeError as exc:
|
||||
if "__init__() got an unexpected keyword argument" not in str(exc):
|
||||
raise exc
|
||||
|
||||
if cls.__INIT_PARAMS_CHECK is not cls:
|
||||
signature = inspect.signature(cls)
|
||||
cls.__INIT_PARAMS = set(signature.parameters.keys())
|
||||
cls.__INIT_PARAMS_CHECK = cls
|
||||
|
||||
api_kwargs = api_kwargs or {}
|
||||
existing_kwargs: JSONDict = {}
|
||||
for key, value in data.items():
|
||||
(existing_kwargs if key in cls.__INIT_PARAMS else api_kwargs)[key] = value
|
||||
|
||||
obj = cls(api_kwargs=api_kwargs, **existing_kwargs)
|
||||
|
||||
obj.set_bot(bot=bot)
|
||||
return obj
|
||||
|
||||
@classmethod
|
||||
def de_json(cls: Type[Tele_co], data: Optional[JSONDict], bot: "Bot") -> Optional[Tele_co]:
|
||||
"""Converts JSON data to a Telegram object.
|
||||
|
||||
Args:
|
||||
data (Dict[:obj:`str`, ...]): The JSON data.
|
||||
bot (:class:`telegram.Bot`): The bot associated with this object.
|
||||
|
||||
Returns:
|
||||
The Telegram object.
|
||||
|
||||
"""
|
||||
return cls._de_json(data=data, bot=bot)
|
||||
|
||||
@classmethod
|
||||
def de_list(
|
||||
cls: Type[Tele_co], data: Optional[List[JSONDict]], bot: "Bot"
|
||||
) -> Tuple[Tele_co, ...]:
|
||||
"""Converts a list of JSON objects to a tuple of Telegram objects.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
||||
* Returns a tuple instead of a list.
|
||||
* Filters out any :obj:`None` values.
|
||||
|
||||
Args:
|
||||
data (List[Dict[:obj:`str`, ...]]): The JSON data.
|
||||
bot (:class:`telegram.Bot`): The bot associated with these objects.
|
||||
|
||||
Returns:
|
||||
A tuple of Telegram objects.
|
||||
|
||||
"""
|
||||
if not data:
|
||||
return ()
|
||||
|
||||
return tuple(obj for obj in (cls.de_json(d, bot) for d in data) if obj is not None)
|
||||
|
||||
@contextmanager
|
||||
def _unfrozen(self: Tele_co) -> Iterator[Tele_co]:
|
||||
"""Context manager to temporarily unfreeze the object. For internal use only.
|
||||
|
||||
Note:
|
||||
with to._unfrozen() as other_to:
|
||||
assert to is other_to
|
||||
"""
|
||||
self._unfreeze()
|
||||
yield self
|
||||
self._freeze()
|
||||
|
||||
def _freeze(self) -> None:
|
||||
self._frozen = True
|
||||
|
||||
def _unfreeze(self) -> None:
|
||||
self._frozen = False
|
||||
|
||||
def _apply_api_kwargs(self, api_kwargs: JSONDict) -> None:
|
||||
"""Loops through the api kwargs and for every key that exists as attribute of the
|
||||
object (and is None), it moves the value from `api_kwargs` to the attribute.
|
||||
*Edits `api_kwargs` in place!*
|
||||
|
||||
This method is currently only called in the unpickling process, i.e. not on "normal" init.
|
||||
This is because
|
||||
* automating this is tricky to get right: It should be called at the *end* of the __init__,
|
||||
preferably only once at the end of the __init__ of the last child class. This could be
|
||||
done via __init_subclass__, but it's hard to not destroy the signature of __init__ in the
|
||||
process.
|
||||
* calling it manually in every __init__ is tedious
|
||||
* There probably is no use case for it anyway. If you manually initialize a TO subclass,
|
||||
then you can pass everything as proper argument.
|
||||
"""
|
||||
# we convert to list to ensure that the list doesn't change length while we loop
|
||||
for key in list(api_kwargs.keys()):
|
||||
if getattr(self, key, True) is None:
|
||||
setattr(self, key, api_kwargs.pop(key))
|
||||
|
||||
def _get_attrs_names(self, include_private: bool) -> Iterator[str]:
|
||||
"""
|
||||
Returns the names of the attributes of this object. This is used to determine which
|
||||
@@ -423,84 +549,6 @@ class TelegramObject:
|
||||
data.pop("_bot", None)
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def _parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]:
|
||||
"""Should be called by subclasses that override de_json to ensure that the input
|
||||
is not altered. Whoever calls de_json might still want to use the original input
|
||||
for something else.
|
||||
"""
|
||||
return None if data is None else data.copy()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls: Type[Tele_co], data: Optional[JSONDict], bot: "Bot") -> Optional[Tele_co]:
|
||||
"""Converts JSON data to a Telegram object.
|
||||
|
||||
Args:
|
||||
data (Dict[:obj:`str`, ...]): The JSON data.
|
||||
bot (:class:`telegram.Bot`): The bot associated with this object.
|
||||
|
||||
Returns:
|
||||
The Telegram object.
|
||||
|
||||
"""
|
||||
return cls._de_json(data=data, bot=bot)
|
||||
|
||||
@classmethod
|
||||
def _de_json(
|
||||
cls: Type[Tele_co],
|
||||
data: Optional[JSONDict],
|
||||
bot: "Bot",
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> Optional[Tele_co]:
|
||||
if data is None:
|
||||
return None
|
||||
|
||||
# try-except is significantly faster in case we already have a correct argument set
|
||||
try:
|
||||
obj = cls(**data, api_kwargs=api_kwargs)
|
||||
except TypeError as exc:
|
||||
if "__init__() got an unexpected keyword argument" not in str(exc):
|
||||
raise exc
|
||||
|
||||
if cls.__INIT_PARAMS_CHECK is not cls:
|
||||
signature = inspect.signature(cls)
|
||||
cls.__INIT_PARAMS = set(signature.parameters.keys())
|
||||
cls.__INIT_PARAMS_CHECK = cls
|
||||
|
||||
api_kwargs = api_kwargs or {}
|
||||
existing_kwargs: JSONDict = {}
|
||||
for key, value in data.items():
|
||||
(existing_kwargs if key in cls.__INIT_PARAMS else api_kwargs)[key] = value
|
||||
|
||||
obj = cls(api_kwargs=api_kwargs, **existing_kwargs)
|
||||
|
||||
obj.set_bot(bot=bot)
|
||||
return obj
|
||||
|
||||
@classmethod
|
||||
def de_list(
|
||||
cls: Type[Tele_co], data: Optional[List[JSONDict]], bot: "Bot"
|
||||
) -> Tuple[Tele_co, ...]:
|
||||
"""Converts a list of JSON objects to a tuple of Telegram objects.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
||||
* Returns a tuple instead of a list.
|
||||
* Filters out any :obj:`None` values.
|
||||
|
||||
Args:
|
||||
data (List[Dict[:obj:`str`, ...]]): The JSON data.
|
||||
bot (:class:`telegram.Bot`): The bot associated with these objects.
|
||||
|
||||
Returns:
|
||||
A tuple of Telegram objects.
|
||||
|
||||
"""
|
||||
if not data:
|
||||
return ()
|
||||
|
||||
return tuple(obj for obj in (cls.de_json(d, bot) for d in data) if obj is not None)
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""Gives a JSON representation of object.
|
||||
|
||||
@@ -596,51 +644,3 @@ class TelegramObject:
|
||||
bot (:class:`telegram.Bot` | :obj:`None`): The bot instance.
|
||||
"""
|
||||
self._bot = bot
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
"""Compares this object with :paramref:`other` in terms of equality.
|
||||
If this object and :paramref:`other` are `not` objects of the same class,
|
||||
this comparison will fall back to Python's default implementation of :meth:`object.__eq__`.
|
||||
Otherwise, both objects may be compared in terms of equality, if the corresponding
|
||||
subclass of :class:`TelegramObject` has defined a set of attributes to compare and
|
||||
the objects are considered to be equal, if all of these attributes are equal.
|
||||
If the subclass has not defined a set of attributes to compare, a warning will be issued.
|
||||
|
||||
Tip:
|
||||
If instances of a class in the :mod:`telegram` module are comparable in terms of
|
||||
equality, the documentation of the class will state the attributes that will be used
|
||||
for this comparison.
|
||||
|
||||
Args:
|
||||
other (:obj:`object`): The object to compare with.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
"""
|
||||
if isinstance(other, self.__class__):
|
||||
if not self._id_attrs:
|
||||
warn(
|
||||
f"Objects of type {self.__class__.__name__} can not be meaningfully tested for"
|
||||
" equivalence.",
|
||||
stacklevel=2,
|
||||
)
|
||||
if not other._id_attrs:
|
||||
warn(
|
||||
f"Objects of type {other.__class__.__name__} can not be meaningfully tested"
|
||||
" for equivalence.",
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._id_attrs == other._id_attrs
|
||||
return super().__eq__(other)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
"""Builds a hash value for this object such that the hash of two objects is equal if and
|
||||
only if the objects are equal in terms of :meth:`__eq__`.
|
||||
|
||||
Returns:
|
||||
:obj:`int`
|
||||
"""
|
||||
if self._id_attrs:
|
||||
return hash((self.__class__, self._id_attrs))
|
||||
return super().__hash__()
|
||||
|
||||
+29
-36
@@ -25,14 +25,7 @@ from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton
|
||||
from telegram._menubutton import MenuButton
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import (
|
||||
CorrectOptionID,
|
||||
DVInput,
|
||||
FileInput,
|
||||
JSONDict,
|
||||
ODVInput,
|
||||
ReplyMarkup,
|
||||
)
|
||||
from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup
|
||||
from telegram.helpers import mention_html as helpers_mention_html
|
||||
from telegram.helpers import mention_markdown as helpers_mention_markdown
|
||||
|
||||
@@ -153,7 +146,7 @@ class User(TelegramObject):
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Required
|
||||
self.id: int = id # pylint: disable=invalid-name
|
||||
self.id: int = id
|
||||
self.first_name: str = first_name
|
||||
self.is_bot: bool = is_bot
|
||||
# Optionals
|
||||
@@ -391,7 +384,7 @@ class User(TelegramObject):
|
||||
text: str,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -441,7 +434,7 @@ class User(TelegramObject):
|
||||
self,
|
||||
photo: Union[FileInput, "PhotoSize"],
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -453,7 +446,7 @@ class User(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -504,7 +497,7 @@ class User(TelegramObject):
|
||||
message_thread_id: Optional[int] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -551,7 +544,7 @@ class User(TelegramObject):
|
||||
performer: Optional[str] = None,
|
||||
title: Optional[str] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -563,7 +556,7 @@ class User(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -648,7 +641,7 @@ class User(TelegramObject):
|
||||
phone_number: Optional[str] = None,
|
||||
first_name: Optional[str] = None,
|
||||
last_name: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
vcard: Optional[str] = None,
|
||||
@@ -745,7 +738,7 @@ class User(TelegramObject):
|
||||
self,
|
||||
document: Union[FileInput, "Document"],
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -758,7 +751,7 @@ class User(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -801,7 +794,7 @@ class User(TelegramObject):
|
||||
async def send_game(
|
||||
self,
|
||||
game_short_name: str,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -861,7 +854,7 @@ class User(TelegramObject):
|
||||
need_email: Optional[bool] = None,
|
||||
need_shipping_address: Optional[bool] = None,
|
||||
is_flexible: Optional[bool] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
provider_data: Optional[Union[str, object]] = None,
|
||||
@@ -942,7 +935,7 @@ class User(TelegramObject):
|
||||
self,
|
||||
latitude: Optional[float] = None,
|
||||
longitude: Optional[float] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
live_period: Optional[int] = None,
|
||||
@@ -1003,7 +996,7 @@ class User(TelegramObject):
|
||||
height: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1015,7 +1008,7 @@ class User(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1061,7 +1054,7 @@ class User(TelegramObject):
|
||||
async def send_sticker(
|
||||
self,
|
||||
sticker: Union[FileInput, "Sticker"],
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1070,7 +1063,7 @@ class User(TelegramObject):
|
||||
emoji: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1110,7 +1103,7 @@ class User(TelegramObject):
|
||||
video: Union[FileInput, "Video"],
|
||||
duration: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
width: Optional[int] = None,
|
||||
@@ -1126,7 +1119,7 @@ class User(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1177,7 +1170,7 @@ class User(TelegramObject):
|
||||
title: Optional[str] = None,
|
||||
address: Optional[str] = None,
|
||||
foursquare_id: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
foursquare_type: Optional[str] = None,
|
||||
@@ -1236,7 +1229,7 @@ class User(TelegramObject):
|
||||
video_note: Union[FileInput, "VideoNote"],
|
||||
duration: Optional[int] = None,
|
||||
length: Optional[int] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -1246,7 +1239,7 @@ class User(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1289,7 +1282,7 @@ class User(TelegramObject):
|
||||
voice: Union[FileInput, "Voice"],
|
||||
duration: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -1300,7 +1293,7 @@ class User(TelegramObject):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1413,9 +1406,9 @@ class User(TelegramObject):
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
@@ -1466,9 +1459,9 @@ class User(TelegramObject):
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
|
||||
@@ -53,7 +53,7 @@ def _localize(datetime: dtm.datetime, tzinfo: dtm.tzinfo) -> dtm.datetime:
|
||||
|
||||
|
||||
def to_float_timestamp(
|
||||
time_object: Union[int, float, dtm.timedelta, dtm.datetime, dtm.time],
|
||||
time_object: Union[float, dtm.timedelta, dtm.datetime, dtm.time],
|
||||
reference_timestamp: Optional[float] = None,
|
||||
tzinfo: Optional[dtm.tzinfo] = None,
|
||||
) -> float:
|
||||
@@ -65,12 +65,11 @@ def to_float_timestamp(
|
||||
to be in UTC, if ``bot`` is not passed or ``bot.defaults`` is :obj:`None`.
|
||||
|
||||
Args:
|
||||
time_object (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \
|
||||
time_object (:obj:`float` | :obj:`datetime.timedelta` | \
|
||||
:obj:`datetime.datetime` | :obj:`datetime.time`):
|
||||
Time value to convert. The semantics of this parameter will depend on its type:
|
||||
|
||||
* :obj:`int` or :obj:`float` will be interpreted as "seconds from
|
||||
:paramref:`reference_t`"
|
||||
* :obj:`float` will be interpreted as "seconds from :paramref:`reference_t`"
|
||||
* :obj:`datetime.timedelta` will be interpreted as
|
||||
"time increment from :paramref:`reference_timestamp`"
|
||||
* :obj:`datetime.datetime` will be interpreted as an absolute date/time value
|
||||
@@ -148,7 +147,7 @@ def to_float_timestamp(
|
||||
|
||||
|
||||
def to_timestamp(
|
||||
dt_obj: Union[int, float, dtm.timedelta, dtm.datetime, dtm.time, None],
|
||||
dt_obj: Union[float, dtm.timedelta, dtm.datetime, dtm.time, None],
|
||||
reference_timestamp: Optional[float] = None,
|
||||
tzinfo: Optional[dtm.tzinfo] = None,
|
||||
) -> Optional[int]:
|
||||
|
||||
@@ -88,6 +88,14 @@ class DefaultValue(Generic[DVType]):
|
||||
def __bool__(self) -> bool:
|
||||
return bool(self.value)
|
||||
|
||||
# This is mostly here for readability during debugging
|
||||
def __str__(self) -> str:
|
||||
return f"DefaultValue({self.value})"
|
||||
|
||||
# This is here to have the default instances nicely rendered in the docs
|
||||
def __repr__(self) -> str:
|
||||
return repr(self.value)
|
||||
|
||||
@overload
|
||||
@staticmethod
|
||||
def get_value(obj: "DefaultValue[OT]") -> OT:
|
||||
@@ -112,14 +120,6 @@ class DefaultValue(Generic[DVType]):
|
||||
"""
|
||||
return obj.value if isinstance(obj, DefaultValue) else obj
|
||||
|
||||
# This is mostly here for readability during debugging
|
||||
def __str__(self) -> str:
|
||||
return f"DefaultValue({self.value})"
|
||||
|
||||
# This is here to have the default instances nicely rendered in the docs
|
||||
def __repr__(self) -> str:
|
||||
return repr(self.value)
|
||||
|
||||
|
||||
DEFAULT_NONE: DefaultValue[None] = DefaultValue(None)
|
||||
""":class:`DefaultValue`: Default :obj:`None`"""
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains auxiliary functionality for building strings for __repr__ method.
|
||||
|
||||
Warning:
|
||||
Contents of this module are intended to be used internally by the library and *not* by the
|
||||
user. Changes to this module are not considered breaking changes and may not be documented in
|
||||
the changelog.
|
||||
"""
|
||||
from typing import Any
|
||||
|
||||
|
||||
def build_repr_with_selected_attrs(obj: object, **kwargs: Any) -> str:
|
||||
"""Create ``__repr__`` string in the style ``Classname[arg1=1, arg2=2]``.
|
||||
|
||||
The square brackets emphasize the fact that an object cannot be instantiated
|
||||
from this string.
|
||||
|
||||
Attributes that are to be used in the representation, are passed as kwargs.
|
||||
"""
|
||||
return (
|
||||
f"{obj.__class__.__name__}"
|
||||
# square brackets emphasize that an object cannot be instantiated with these params
|
||||
f"[{', '.join(_stringify(name, value) for name, value in kwargs.items())}]"
|
||||
)
|
||||
|
||||
|
||||
def _stringify(key: str, val: Any) -> str:
|
||||
return f"{key}={val.__qualname__ if callable(val) else val}"
|
||||
@@ -95,3 +95,9 @@ HTTPVersion = Literal["1.1", "2.0", "2"]
|
||||
CorrectOptionID = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
MarkdownVersion = Literal[1, 2]
|
||||
|
||||
SocketOpt = Union[
|
||||
Tuple[int, int, int],
|
||||
Tuple[int, int, Union[bytes, bytearray]],
|
||||
Tuple[int, int, None, int],
|
||||
]
|
||||
|
||||
@@ -51,7 +51,7 @@ class Version(NamedTuple):
|
||||
|
||||
|
||||
__version_info__: Final[Version] = Version(
|
||||
major=20, minor=5, micro=0, releaselevel="final", serial=0
|
||||
major=20, minor=7, micro=0, releaselevel="final", serial=0
|
||||
)
|
||||
__version__: Final[str] = str(__version_info__)
|
||||
|
||||
|
||||
@@ -39,12 +39,12 @@ class WebAppInfo(TelegramObject):
|
||||
Args:
|
||||
url (:obj:`str`): An HTTPS URL of a Web App to be opened with additional data as specified
|
||||
in `Initializing Web Apps \
|
||||
<https://core.telegram.org/bots/webapps#initializing-web-apps>`_.
|
||||
<https://core.telegram.org/bots/webapps#initializing-mini-apps>`_.
|
||||
|
||||
Attributes:
|
||||
url (:obj:`str`): An HTTPS URL of a Web App to be opened with additional data as specified
|
||||
in `Initializing Web Apps \
|
||||
<https://core.telegram.org/bots/webapps#initializing-web-apps>`_.
|
||||
<https://core.telegram.org/bots/webapps#initializing-mini-apps>`_.
|
||||
"""
|
||||
|
||||
__slots__ = ("url",)
|
||||
|
||||
@@ -26,28 +26,63 @@ from telegram._utils.types import JSONDict
|
||||
class WriteAccessAllowed(TelegramObject):
|
||||
"""
|
||||
This object represents a service message about a user allowing a bot to write messages after
|
||||
adding the bot to the attachment menu or launching a Web App from a link.
|
||||
adding it to the attachment menu, launching a Web App from a link, or accepting an explicit
|
||||
request from a Web App sent by the method
|
||||
`requestWriteAccess <https://core.telegram.org/bots/webapps#initializing-mini-apps>`_.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`web_app_name` is equal.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
.. versionchanged:: 20.6
|
||||
Added custom equality comparison for objects of this class.
|
||||
|
||||
Args:
|
||||
web_app_name (:obj:`str`, optional): Name of the Web App which was launched from a link.
|
||||
web_app_name (:obj:`str`, optional): Name of the Web App, if the access was granted when
|
||||
the Web App was launched from a link.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
from_request (:obj:`bool`, optional): :obj:`True`, if the access was granted after the user
|
||||
accepted an explicit request from a Web App sent by the method
|
||||
`requestWriteAccess <https://core.telegram.org/bots/webapps#initializing-mini-apps>`_.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
from_attachment_menu (:obj:`bool`, optional): :obj:`True`, if the access was granted when
|
||||
the bot was added to the attachment or side menu.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
|
||||
Attributes:
|
||||
web_app_name (:obj:`str`): Optional. Name of the Web App which was launched from a link.
|
||||
web_app_name (:obj:`str`): Optional. Name of the Web App, if the access was granted when
|
||||
the Web App was launched from a link.
|
||||
|
||||
.. versionadded:: 20.3
|
||||
from_request (:obj:`bool`): Optional. :obj:`True`, if the access was granted after the user
|
||||
accepted an explicit request from a Web App.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
from_attachment_menu (:obj:`bool`): Optional. :obj:`True`, if the access was granted when
|
||||
the bot was added to the attachment or side menu.
|
||||
|
||||
.. versionadded:: 20.6
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("web_app_name",)
|
||||
__slots__ = ("web_app_name", "from_request", "from_attachment_menu")
|
||||
|
||||
def __init__(
|
||||
self, web_app_name: Optional[str] = None, *, api_kwargs: Optional[JSONDict] = None
|
||||
self,
|
||||
web_app_name: Optional[str] = None,
|
||||
from_request: Optional[bool] = None,
|
||||
from_attachment_menu: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.web_app_name: Optional[str] = web_app_name
|
||||
self.from_request: Optional[bool] = from_request
|
||||
self.from_attachment_menu: Optional[bool] = from_attachment_menu
|
||||
|
||||
self._id_attrs = (self.web_app_name,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@@ -116,7 +116,7 @@ class _BotAPIVersion(NamedTuple):
|
||||
#: :data:`telegram.__bot_api_version_info__`.
|
||||
#:
|
||||
#: .. versionadded:: 20.0
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=6, minor=8)
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=6, minor=9)
|
||||
#: :obj:`str`: Telegram Bot API
|
||||
#: version supported by this version of `python-telegram-bot`. Also available as
|
||||
#: :data:`telegram.__bot_api_version__`.
|
||||
|
||||
+103
-53
@@ -54,6 +54,7 @@ from typing import (
|
||||
from telegram._update import Update
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE, DEFAULT_TRUE, DefaultValue
|
||||
from telegram._utils.logging import get_logger
|
||||
from telegram._utils.repr import build_repr_with_selected_attrs
|
||||
from telegram._utils.types import SCT, DVType, ODVInput
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.error import TelegramError
|
||||
@@ -80,7 +81,6 @@ _AppType = TypeVar("_AppType", bound="Application") # pylint: disable=invalid-n
|
||||
_STOP_SIGNAL = object()
|
||||
_DEFAULT_0 = DefaultValue(0)
|
||||
|
||||
|
||||
# Since python 3.12, the coroutine passed to create_task should not be an (async) generator. Remove
|
||||
# this check when we drop support for python 3.11.
|
||||
if sys.version_info >= (3, 12):
|
||||
@@ -90,7 +90,6 @@ else:
|
||||
|
||||
_ErrorCoroType = Optional[_CoroType[RT]]
|
||||
|
||||
|
||||
_LOGGER = get_logger(__name__)
|
||||
|
||||
|
||||
@@ -150,6 +149,8 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
finally:
|
||||
await application.shutdown()
|
||||
|
||||
.. seealso:: :meth:`__aenter__` and :meth:`__aexit__`.
|
||||
|
||||
Examples:
|
||||
:any:`Echo Bot <examples.echobot>`
|
||||
|
||||
@@ -345,11 +346,44 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
self.__update_persistence_lock = asyncio.Lock()
|
||||
self.__create_task_tasks: Set[asyncio.Task] = set() # Used for awaiting tasks upon exit
|
||||
|
||||
def _check_initialized(self) -> None:
|
||||
if not self._initialized:
|
||||
raise RuntimeError(
|
||||
"This Application was not initialized via `Application.initialize`!"
|
||||
)
|
||||
async def __aenter__(self: _AppType) -> _AppType: # noqa: PYI019
|
||||
"""|async_context_manager| :meth:`initializes <initialize>` the App.
|
||||
|
||||
Returns:
|
||||
The initialized App instance.
|
||||
|
||||
Raises:
|
||||
:exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown`
|
||||
is called in this case.
|
||||
"""
|
||||
try:
|
||||
await self.initialize()
|
||||
return self
|
||||
except Exception as exc:
|
||||
await self.shutdown()
|
||||
raise exc
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[Type[BaseException]],
|
||||
exc_val: Optional[BaseException],
|
||||
exc_tb: Optional[TracebackType],
|
||||
) -> None:
|
||||
"""|async_context_manager| :meth:`shuts down <shutdown>` the App."""
|
||||
# Make sure not to return `True` so that exceptions are not suppressed
|
||||
# https://docs.python.org/3/reference/datamodel.html?#object.__aexit__
|
||||
await self.shutdown()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Give a string representation of the application in the form ``Application[bot=...]``.
|
||||
|
||||
As this class doesn't implement :meth:`object.__str__`, the default implementation
|
||||
will be used, which is equivalent to :meth:`__repr__`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`
|
||||
"""
|
||||
return build_repr_with_selected_attrs(self, bot=self.bot)
|
||||
|
||||
@property
|
||||
def running(self) -> bool:
|
||||
@@ -400,6 +434,27 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
"""
|
||||
return self._update_processor
|
||||
|
||||
@staticmethod
|
||||
def _raise_system_exit() -> NoReturn:
|
||||
raise SystemExit
|
||||
|
||||
@staticmethod
|
||||
def builder() -> "InitApplicationBuilder":
|
||||
"""Convenience method. Returns a new :class:`telegram.ext.ApplicationBuilder`.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
"""
|
||||
# Unfortunately this needs to be here due to cyclical imports
|
||||
from telegram.ext import ApplicationBuilder # pylint: disable=import-outside-toplevel
|
||||
|
||||
return ApplicationBuilder()
|
||||
|
||||
def _check_initialized(self) -> None:
|
||||
if not self._initialized:
|
||||
raise RuntimeError(
|
||||
"This Application was not initialized via `Application.initialize`!"
|
||||
)
|
||||
|
||||
async def initialize(self) -> None:
|
||||
"""Initializes the Application by initializing:
|
||||
|
||||
@@ -486,26 +541,6 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
|
||||
self._initialized = False
|
||||
|
||||
async def __aenter__(self: _AppType) -> _AppType:
|
||||
"""Simple context manager which initializes the App."""
|
||||
try:
|
||||
await self.initialize()
|
||||
return self
|
||||
except Exception as exc:
|
||||
await self.shutdown()
|
||||
raise exc
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[Type[BaseException]],
|
||||
exc_val: Optional[BaseException],
|
||||
exc_tb: Optional[TracebackType],
|
||||
) -> None:
|
||||
"""Shutdown the App from the context manager."""
|
||||
# Make sure not to return `True` so that exceptions are not suppressed
|
||||
# https://docs.python.org/3/reference/datamodel.html?#object.__aexit__
|
||||
await self.shutdown()
|
||||
|
||||
async def _initialize_persistence(self) -> None:
|
||||
"""This method basically just loads all the data by awaiting the BP methods"""
|
||||
if not self.persistence:
|
||||
@@ -535,17 +570,6 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
persistent_data
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def builder() -> "InitApplicationBuilder":
|
||||
"""Convenience method. Returns a new :class:`telegram.ext.ApplicationBuilder`.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
"""
|
||||
# Unfortunately this needs to be here due to cyclical imports
|
||||
from telegram.ext import ApplicationBuilder # pylint: disable=import-outside-toplevel
|
||||
|
||||
return ApplicationBuilder()
|
||||
|
||||
async def start(self) -> None:
|
||||
"""Starts
|
||||
|
||||
@@ -676,7 +700,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
poll_interval: float = 0.0,
|
||||
timeout: int = 10,
|
||||
bootstrap_retries: int = -1,
|
||||
read_timeout: float = 2,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -721,16 +745,37 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
* > 0 - retry up to X times
|
||||
|
||||
read_timeout (:obj:`float`, optional): Value to pass to
|
||||
:paramref:`telegram.Bot.get_updates.read_timeout`. Defaults to ``2``.
|
||||
:paramref:`telegram.Bot.get_updates.read_timeout`. Defaults to
|
||||
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
|
||||
|
||||
.. versionchanged:: 20.7
|
||||
Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE` instead of
|
||||
``2``.
|
||||
|
||||
.. deprecated:: 20.7
|
||||
Deprecated in favor of setting the timeout via
|
||||
:meth:`telegram.ext.ApplicationBuilder.get_updates_read_timeout`.
|
||||
write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
|
||||
:paramref:`telegram.Bot.get_updates.write_timeout`. Defaults to
|
||||
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
|
||||
|
||||
.. deprecated:: 20.7
|
||||
Deprecated in favor of setting the timeout via
|
||||
:meth:`telegram.ext.ApplicationBuilder.get_updates_write_timeout`.
|
||||
connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
|
||||
:paramref:`telegram.Bot.get_updates.connect_timeout`. Defaults to
|
||||
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
|
||||
|
||||
.. deprecated:: 20.7
|
||||
Deprecated in favor of setting the timeout via
|
||||
:meth:`telegram.ext.ApplicationBuilder.get_updates_connect_timeout`.
|
||||
pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
|
||||
:paramref:`telegram.Bot.get_updates.pool_timeout`. Defaults to
|
||||
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
|
||||
|
||||
.. deprecated:: 20.7
|
||||
Deprecated in favor of setting the timeout via
|
||||
:meth:`telegram.ext.ApplicationBuilder.get_updates_pool_timeout`.
|
||||
drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on
|
||||
Telegram servers before actually starting to poll. Default is :obj:`False`.
|
||||
allowed_updates (List[:obj:`str`], optional): Passed to
|
||||
@@ -759,6 +804,14 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
"Application.run_polling is only available if the application has an Updater."
|
||||
)
|
||||
|
||||
if (read_timeout, write_timeout, connect_timeout, pool_timeout) != ((DEFAULT_NONE,) * 4):
|
||||
warn(
|
||||
"Setting timeouts via `Application.run_polling` is deprecated. "
|
||||
"Please use `ApplicationBuilder.get_updates_*_timeout` instead.",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
def error_callback(exc: TelegramError) -> None:
|
||||
self.create_task(self.process_error(error=exc, update=None))
|
||||
|
||||
@@ -912,10 +965,6 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
stop_signals=stop_signals,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _raise_system_exit() -> NoReturn:
|
||||
raise SystemExit
|
||||
|
||||
def __run(
|
||||
self,
|
||||
updater_coroutine: Coroutine,
|
||||
@@ -938,7 +987,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
warn(
|
||||
f"Could not add signal handlers for the stop signals {stop_signals} due to "
|
||||
f"exception `{exc!r}`. If your event loop does not implement `add_signal_handler`,"
|
||||
f" please pass `stop_signals=None`.",
|
||||
" please pass `stop_signals=None`.",
|
||||
stacklevel=3,
|
||||
)
|
||||
|
||||
@@ -1066,12 +1115,11 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
return await asyncio.create_task(coroutine)
|
||||
# If user uses generator in python 3.12+, Exception will happen and we cannot do
|
||||
# anything about it. (hence the type ignore if mypy is run on python 3.12-)
|
||||
return await coroutine # type: ignore
|
||||
return await coroutine # type: ignore[misc]
|
||||
except Exception as exception:
|
||||
if isinstance(exception, ApplicationHandlerStop):
|
||||
warn(
|
||||
"ApplicationHandlerStop is not supported with handlers "
|
||||
"running non-blocking.",
|
||||
"ApplicationHandlerStop is not supported with handlers running non-blocking.",
|
||||
stacklevel=1,
|
||||
)
|
||||
|
||||
@@ -1176,8 +1224,10 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
self.create_task(
|
||||
coroutine,
|
||||
update=update,
|
||||
name=f"Application:{self.bot.id}:process_update_non_blocking"
|
||||
f":{handler}",
|
||||
name=(
|
||||
f"Application:{self.bot.id}:process_update_non_blocking"
|
||||
f":{handler}"
|
||||
),
|
||||
)
|
||||
else:
|
||||
any_blocking = True
|
||||
@@ -1246,7 +1296,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
if not self.persistence:
|
||||
raise ValueError(
|
||||
f"ConversationHandler {handler.name} "
|
||||
f"can not be persistent if application has no persistence"
|
||||
"can not be persistent if application has no persistence"
|
||||
)
|
||||
if self._initialized:
|
||||
self.create_task(
|
||||
@@ -1346,7 +1396,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
chat_id (:obj:`int`): The chat id to delete. The entry will be deleted even if it is
|
||||
not empty.
|
||||
"""
|
||||
self._chat_data.pop(chat_id, None) # type: ignore[arg-type]
|
||||
self._chat_data.pop(chat_id, None)
|
||||
self._chat_ids_to_be_deleted_in_persistence.add(chat_id)
|
||||
|
||||
def drop_user_data(self, user_id: int) -> None:
|
||||
@@ -1365,7 +1415,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
user_id (:obj:`int`): The user id to delete. The entry will be deleted even if it is
|
||||
not empty.
|
||||
"""
|
||||
self._user_data.pop(user_id, None) # type: ignore[arg-type]
|
||||
self._user_data.pop(user_id, None)
|
||||
self._user_ids_to_be_deleted_in_persistence.add(user_id)
|
||||
|
||||
def migrate_chat_data(
|
||||
|
||||
@@ -23,6 +23,7 @@ from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Callable,
|
||||
Collection,
|
||||
Coroutine,
|
||||
Dict,
|
||||
Generic,
|
||||
@@ -32,9 +33,12 @@ from typing import (
|
||||
Union,
|
||||
)
|
||||
|
||||
import httpx
|
||||
|
||||
from telegram._bot import Bot
|
||||
from telegram._utils.defaultvalue import DEFAULT_FALSE, DEFAULT_NONE, DefaultValue
|
||||
from telegram._utils.types import DVInput, DVType, FilePathInput, HTTPVersion, ODVInput
|
||||
from telegram._utils.types import DVInput, DVType, FilePathInput, HTTPVersion, ODVInput, SocketOpt
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.ext._application import Application
|
||||
from telegram.ext._baseupdateprocessor import BaseUpdateProcessor, SimpleUpdateProcessor
|
||||
from telegram.ext._contexttypes import ContextTypes
|
||||
@@ -44,8 +48,10 @@ from telegram.ext._updater import Updater
|
||||
from telegram.ext._utils.types import BD, BT, CCT, CD, JQ, UD
|
||||
from telegram.request import BaseRequest
|
||||
from telegram.request._httpxrequest import HTTPXRequest
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Update
|
||||
from telegram.ext import BasePersistence, BaseRateLimiter, CallbackContext, Defaults
|
||||
from telegram.ext._utils.types import RLARGS
|
||||
|
||||
@@ -66,14 +72,16 @@ _BOT_CHECKS = [
|
||||
("request", "request instance"),
|
||||
("get_updates_request", "get_updates_request instance"),
|
||||
("connection_pool_size", "connection_pool_size"),
|
||||
("proxy_url", "proxy_url"),
|
||||
("proxy", "proxy"),
|
||||
("socket_options", "socket_options"),
|
||||
("pool_timeout", "pool_timeout"),
|
||||
("connect_timeout", "connect_timeout"),
|
||||
("read_timeout", "read_timeout"),
|
||||
("write_timeout", "write_timeout"),
|
||||
("http_version", "http_version"),
|
||||
("get_updates_connection_pool_size", "get_updates_connection_pool_size"),
|
||||
("get_updates_proxy_url", "get_updates_proxy_url"),
|
||||
("get_updates_proxy", "get_updates_proxy"),
|
||||
("get_updates_socket_options", "get_updates_socket_options"),
|
||||
("get_updates_pool_timeout", "get_updates_pool_timeout"),
|
||||
("get_updates_connect_timeout", "get_updates_connect_timeout"),
|
||||
("get_updates_read_timeout", "get_updates_read_timeout"),
|
||||
@@ -136,9 +144,10 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
"_get_updates_connect_timeout",
|
||||
"_get_updates_connection_pool_size",
|
||||
"_get_updates_pool_timeout",
|
||||
"_get_updates_proxy_url",
|
||||
"_get_updates_proxy",
|
||||
"_get_updates_read_timeout",
|
||||
"_get_updates_request",
|
||||
"_get_updates_socket_options",
|
||||
"_get_updates_write_timeout",
|
||||
"_get_updates_http_version",
|
||||
"_job_queue",
|
||||
@@ -149,10 +158,11 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
"_post_stop",
|
||||
"_private_key",
|
||||
"_private_key_password",
|
||||
"_proxy_url",
|
||||
"_proxy",
|
||||
"_rate_limiter",
|
||||
"_read_timeout",
|
||||
"_request",
|
||||
"_socket_options",
|
||||
"_token",
|
||||
"_update_queue",
|
||||
"_updater",
|
||||
@@ -166,14 +176,16 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
self._base_url: DVType[str] = DefaultValue("https://api.telegram.org/bot")
|
||||
self._base_file_url: DVType[str] = DefaultValue("https://api.telegram.org/file/bot")
|
||||
self._connection_pool_size: DVInput[int] = DEFAULT_NONE
|
||||
self._proxy_url: DVInput[str] = DEFAULT_NONE
|
||||
self._proxy: DVInput[Union[str, httpx.Proxy, httpx.URL]] = DEFAULT_NONE
|
||||
self._socket_options: DVInput[Collection[SocketOpt]] = DEFAULT_NONE
|
||||
self._connect_timeout: ODVInput[float] = DEFAULT_NONE
|
||||
self._read_timeout: ODVInput[float] = DEFAULT_NONE
|
||||
self._write_timeout: ODVInput[float] = DEFAULT_NONE
|
||||
self._pool_timeout: ODVInput[float] = DEFAULT_NONE
|
||||
self._request: DVInput[BaseRequest] = DEFAULT_NONE
|
||||
self._get_updates_connection_pool_size: DVInput[int] = DEFAULT_NONE
|
||||
self._get_updates_proxy_url: DVInput[str] = DEFAULT_NONE
|
||||
self._get_updates_proxy: DVInput[Union[str, httpx.Proxy, httpx.URL]] = DEFAULT_NONE
|
||||
self._get_updates_socket_options: DVInput[Collection[SocketOpt]] = DEFAULT_NONE
|
||||
self._get_updates_connect_timeout: ODVInput[float] = DEFAULT_NONE
|
||||
self._get_updates_read_timeout: ODVInput[float] = DEFAULT_NONE
|
||||
self._get_updates_write_timeout: ODVInput[float] = DEFAULT_NONE
|
||||
@@ -186,7 +198,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
self._arbitrary_callback_data: Union[DefaultValue[bool], int] = DEFAULT_FALSE
|
||||
self._local_mode: DVType[bool] = DEFAULT_FALSE
|
||||
self._bot: DVInput[Bot] = DEFAULT_NONE
|
||||
self._update_queue: DVType[Queue] = DefaultValue(Queue())
|
||||
self._update_queue: DVType[Queue[Union[Update, object]]] = DefaultValue(Queue())
|
||||
|
||||
try:
|
||||
self._job_queue: ODVInput[JobQueue] = DefaultValue(JobQueue())
|
||||
@@ -214,7 +226,8 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
if not isinstance(getattr(self, f"{prefix}request"), DefaultValue):
|
||||
return getattr(self, f"{prefix}request")
|
||||
|
||||
proxy_url = DefaultValue.get_value(getattr(self, f"{prefix}proxy_url"))
|
||||
proxy = DefaultValue.get_value(getattr(self, f"{prefix}proxy"))
|
||||
socket_options = DefaultValue.get_value(getattr(self, f"{prefix}socket_options"))
|
||||
if get_updates:
|
||||
connection_pool_size = (
|
||||
DefaultValue.get_value(getattr(self, f"{prefix}connection_pool_size")) or 1
|
||||
@@ -239,8 +252,9 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
|
||||
return HTTPXRequest(
|
||||
connection_pool_size=connection_pool_size,
|
||||
proxy_url=proxy_url,
|
||||
proxy=proxy,
|
||||
http_version=http_version, # type: ignore[arg-type]
|
||||
socket_options=socket_options,
|
||||
**effective_timeouts,
|
||||
)
|
||||
|
||||
@@ -258,7 +272,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
arbitrary_callback_data=DefaultValue.get_value(self._arbitrary_callback_data),
|
||||
request=self._build_request(get_updates=False),
|
||||
get_updates_request=self._build_request(get_updates=True),
|
||||
rate_limiter=DefaultValue.get_value(self._rate_limiter),
|
||||
rate_limiter=DefaultValue.get_value(self._rate_limiter), # type: ignore[arg-type]
|
||||
local_mode=DefaultValue.get_value(self._local_mode),
|
||||
)
|
||||
|
||||
@@ -303,7 +317,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
|
||||
application: Application[
|
||||
BT, CCT, UD, CD, BD, JQ
|
||||
] = DefaultValue.get_value( # pylint: disable=not-callable
|
||||
] = DefaultValue.get_value( # type: ignore[operator] # pylint: disable=not-callable
|
||||
self._application_class
|
||||
)(
|
||||
bot=bot,
|
||||
@@ -311,7 +325,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
updater=updater,
|
||||
update_processor=self._update_processor,
|
||||
job_queue=job_queue,
|
||||
persistence=persistence,
|
||||
persistence=persistence, # type: ignore[arg-type]
|
||||
context_types=DefaultValue.get_value(self._context_types),
|
||||
post_init=self._post_init,
|
||||
post_shutdown=self._post_shutdown,
|
||||
@@ -320,12 +334,12 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
)
|
||||
|
||||
if job_queue is not None:
|
||||
job_queue.set_application(application) # type: ignore[arg-type]
|
||||
job_queue.set_application(application) # type: ignore[arg-type, union-attr]
|
||||
|
||||
if persistence is not None:
|
||||
# This raises an exception if persistence.store_data.callback_data is True
|
||||
# but self.bot is not an instance of ExtBot - so no need to check that later on
|
||||
persistence.set_bot(bot)
|
||||
persistence.set_bot(bot) # type: ignore[union-attr]
|
||||
|
||||
return application
|
||||
|
||||
@@ -419,8 +433,11 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
if not isinstance(getattr(self, f"_{prefix}connection_pool_size"), DefaultValue):
|
||||
raise RuntimeError(_TWO_ARGS_REQ.format(name, "connection_pool_size"))
|
||||
|
||||
if not isinstance(getattr(self, f"_{prefix}proxy_url"), DefaultValue):
|
||||
raise RuntimeError(_TWO_ARGS_REQ.format(name, "proxy_url"))
|
||||
if not isinstance(getattr(self, f"_{prefix}proxy"), DefaultValue):
|
||||
raise RuntimeError(_TWO_ARGS_REQ.format(name, "proxy"))
|
||||
|
||||
if not isinstance(getattr(self, f"_{prefix}socket_options"), DefaultValue):
|
||||
raise RuntimeError(_TWO_ARGS_REQ.format(name, "socket_options"))
|
||||
|
||||
if not isinstance(getattr(self, f"_{prefix}http_version"), DefaultValue):
|
||||
raise RuntimeError(_TWO_ARGS_REQ.format(name, "http_version"))
|
||||
@@ -486,21 +503,64 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
return self
|
||||
|
||||
def proxy_url(self: BuilderType, proxy_url: str) -> BuilderType:
|
||||
"""Sets the proxy for the :paramref:`~telegram.request.HTTPXRequest.proxy_url`
|
||||
parameter of :attr:`telegram.Bot.request`. Defaults to :obj:`None`.
|
||||
"""Legacy name for :meth:`proxy`, kept for backward compatibility.
|
||||
|
||||
.. seealso:: :meth:`get_updates_proxy`
|
||||
|
||||
.. seealso:: :meth:`get_updates_proxy_url`
|
||||
.. deprecated:: 20.7
|
||||
|
||||
Args:
|
||||
proxy_url (:obj:`str`): The URL to the proxy server. See
|
||||
:paramref:`telegram.request.HTTPXRequest.proxy_url` for more information.
|
||||
proxy_url (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``): See
|
||||
:paramref:`telegram.ext.ApplicationBuilder.proxy.proxy`.
|
||||
|
||||
Returns:
|
||||
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
||||
"""
|
||||
self._request_param_check(name="proxy_url", get_updates=False)
|
||||
self._proxy_url = proxy_url
|
||||
warn(
|
||||
"`ApplicationBuilder.proxy_url` is deprecated since version "
|
||||
"20.7. Use `ApplicationBuilder.proxy` instead.",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.proxy(proxy_url)
|
||||
|
||||
def proxy(self: BuilderType, proxy: Union[str, httpx.Proxy, httpx.URL]) -> BuilderType:
|
||||
"""Sets the proxy for the :paramref:`~telegram.request.HTTPXRequest.proxy`
|
||||
parameter of :attr:`telegram.Bot.request`. Defaults to :obj:`None`.
|
||||
|
||||
.. seealso:: :meth:`get_updates_proxy`
|
||||
|
||||
.. versionadded:: 20.7
|
||||
|
||||
Args:
|
||||
proxy (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``): The URL to a proxy
|
||||
server, a ``httpx.Proxy`` object or a ``httpx.URL`` object. See
|
||||
:paramref:`telegram.request.HTTPXRequest.proxy` for more information.
|
||||
|
||||
Returns:
|
||||
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
||||
"""
|
||||
self._request_param_check(name="proxy", get_updates=False)
|
||||
self._proxy = proxy
|
||||
return self
|
||||
|
||||
def socket_options(self: BuilderType, socket_options: Collection[SocketOpt]) -> BuilderType:
|
||||
"""Sets the options for the :paramref:`~telegram.request.HTTPXRequest.socket_options`
|
||||
parameter of :attr:`telegram.Bot.request`. Defaults to :obj:`None`.
|
||||
|
||||
.. seealso:: :meth:`get_updates_socket_options`
|
||||
|
||||
.. versionadded:: 20.7
|
||||
|
||||
Args:
|
||||
socket_options (Collection[:obj:`tuple`], optional): Socket options. See
|
||||
:paramref:`telegram.request.HTTPXRequest.socket_options` for more information.
|
||||
|
||||
Returns:
|
||||
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
||||
"""
|
||||
self._request_param_check(name="socket_options", get_updates=False)
|
||||
self._socket_options = socket_options
|
||||
return self
|
||||
|
||||
def connect_timeout(self: BuilderType, connect_timeout: Optional[float]) -> BuilderType:
|
||||
@@ -655,21 +715,68 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||
return self
|
||||
|
||||
def get_updates_proxy_url(self: BuilderType, get_updates_proxy_url: str) -> BuilderType:
|
||||
"""Sets the proxy for the :paramref:`telegram.request.HTTPXRequest.proxy_url`
|
||||
parameter which is used for :meth:`telegram.Bot.get_updates`. Defaults to :obj:`None`.
|
||||
"""Legacy name for :meth:`get_updates_proxy`, kept for backward compatibility.
|
||||
|
||||
.. seealso:: :meth:`proxy`
|
||||
|
||||
.. seealso:: :meth:`proxy_url`
|
||||
.. deprecated:: 20.7
|
||||
|
||||
Args:
|
||||
get_updates_proxy_url (:obj:`str`): The URL to the proxy server. See
|
||||
:paramref:`telegram.request.HTTPXRequest.proxy_url` for more information.
|
||||
get_updates_proxy_url (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``): See
|
||||
:paramref:`telegram.ext.ApplicationBuilder.get_updates_proxy.get_updates_proxy`.
|
||||
|
||||
Returns:
|
||||
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
||||
"""
|
||||
self._request_param_check(name="proxy_url", get_updates=True)
|
||||
self._get_updates_proxy_url = get_updates_proxy_url
|
||||
warn(
|
||||
"`ApplicationBuilder.get_updates_proxy_url` is deprecated since version "
|
||||
"20.7. Use `ApplicationBuilder.get_updates_proxy` instead.",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.get_updates_proxy(get_updates_proxy_url)
|
||||
|
||||
def get_updates_proxy(
|
||||
self: BuilderType, get_updates_proxy: Union[str, httpx.Proxy, httpx.URL]
|
||||
) -> BuilderType:
|
||||
"""Sets the proxy for the :paramref:`telegram.request.HTTPXRequest.proxy`
|
||||
parameter which is used for :meth:`telegram.Bot.get_updates`. Defaults to :obj:`None`.
|
||||
|
||||
.. seealso:: :meth:`proxy`
|
||||
|
||||
.. versionadded:: 20.7
|
||||
|
||||
Args:
|
||||
proxy (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``): The URL to a proxy server,
|
||||
a ``httpx.Proxy`` object or a ``httpx.URL`` object. See
|
||||
:paramref:`telegram.request.HTTPXRequest.proxy` for more information.
|
||||
|
||||
Returns:
|
||||
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
||||
"""
|
||||
self._request_param_check(name="proxy", get_updates=True)
|
||||
self._get_updates_proxy = get_updates_proxy
|
||||
return self
|
||||
|
||||
def get_updates_socket_options(
|
||||
self: BuilderType, get_updates_socket_options: Collection[SocketOpt]
|
||||
) -> BuilderType:
|
||||
"""Sets the options for the :paramref:`~telegram.request.HTTPXRequest.socket_options`
|
||||
parameter of :paramref:`telegram.Bot.get_updates_request`. Defaults to :obj:`None`.
|
||||
|
||||
.. seealso:: :meth:`socket_options`
|
||||
|
||||
.. versionadded:: 20.7
|
||||
|
||||
Args:
|
||||
get_updates_socket_options (Collection[:obj:`tuple`], optional): Socket options. See
|
||||
:paramref:`telegram.request.HTTPXRequest.socket_options` for more information.
|
||||
|
||||
Returns:
|
||||
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
||||
"""
|
||||
self._request_param_check(name="socket_options", get_updates=True)
|
||||
self._get_updates_socket_options = get_updates_socket_options
|
||||
return self
|
||||
|
||||
def get_updates_connect_timeout(
|
||||
|
||||
@@ -21,6 +21,7 @@ from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union
|
||||
|
||||
from telegram._utils.defaultvalue import DEFAULT_TRUE
|
||||
from telegram._utils.repr import build_repr_with_selected_attrs
|
||||
from telegram._utils.types import DVType
|
||||
from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
|
||||
@@ -95,6 +96,21 @@ class BaseHandler(Generic[UT, CCT], ABC):
|
||||
self.callback: HandlerCallback[UT, CCT, RT] = callback
|
||||
self.block: DVType[bool] = block
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Give a string representation of the handler in the form ``ClassName[callback=...]``.
|
||||
|
||||
As this class doesn't implement :meth:`object.__str__`, the default implementation
|
||||
will be used, which is equivalent to :meth:`__repr__`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`
|
||||
"""
|
||||
try:
|
||||
callback_name = self.callback.__qualname__
|
||||
except AttributeError:
|
||||
callback_name = repr(self.callback)
|
||||
return build_repr_with_selected_attrs(self, callback=callback_name)
|
||||
|
||||
@abstractmethod
|
||||
def check_update(self, update: object) -> Optional[Union[bool, object]]:
|
||||
"""
|
||||
|
||||
@@ -27,6 +27,25 @@ class BaseUpdateProcessor(ABC):
|
||||
"""An abstract base class for update processors. You can use this class to implement
|
||||
your own update processor.
|
||||
|
||||
Instances of this class can be used as asyncio context managers, where
|
||||
|
||||
.. code:: python
|
||||
|
||||
async with processor:
|
||||
# code
|
||||
|
||||
is roughly equivalent to
|
||||
|
||||
.. code:: python
|
||||
|
||||
try:
|
||||
await processor.initialize()
|
||||
# code
|
||||
finally:
|
||||
await processor.shutdown()
|
||||
|
||||
.. seealso:: :meth:`__aenter__` and :meth:`__aexit__`.
|
||||
|
||||
.. seealso:: :wiki:`Concurrency`
|
||||
|
||||
.. versionadded:: 20.4
|
||||
@@ -48,6 +67,32 @@ class BaseUpdateProcessor(ABC):
|
||||
raise ValueError("`max_concurrent_updates` must be a positive integer!")
|
||||
self._semaphore = BoundedSemaphore(self.max_concurrent_updates)
|
||||
|
||||
async def __aenter__(self) -> "BaseUpdateProcessor":
|
||||
"""|async_context_manager| :meth:`initializes <initialize>` the Processor.
|
||||
|
||||
Returns:
|
||||
The initialized Processor instance.
|
||||
|
||||
Raises:
|
||||
:exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown`
|
||||
is called in this case.
|
||||
"""
|
||||
try:
|
||||
await self.initialize()
|
||||
return self
|
||||
except Exception as exc:
|
||||
await self.shutdown()
|
||||
raise exc
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[Type[BaseException]],
|
||||
exc_val: Optional[BaseException],
|
||||
exc_tb: Optional[TracebackType],
|
||||
) -> None:
|
||||
"""|async_context_manager| :meth:`shuts down <shutdown>` the Processor."""
|
||||
await self.shutdown()
|
||||
|
||||
@property
|
||||
def max_concurrent_updates(self) -> int:
|
||||
""":obj:`int`: The maximum number of updates that can be processed concurrently."""
|
||||
@@ -105,24 +150,6 @@ class BaseUpdateProcessor(ABC):
|
||||
async with self._semaphore:
|
||||
await self.do_process_update(update, coroutine)
|
||||
|
||||
async def __aenter__(self) -> "BaseUpdateProcessor":
|
||||
"""Simple context manager which initializes the Processor."""
|
||||
try:
|
||||
await self.initialize()
|
||||
return self
|
||||
except Exception as exc:
|
||||
await self.shutdown()
|
||||
raise exc
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[Type[BaseException]],
|
||||
exc_val: Optional[BaseException],
|
||||
exc_tb: Optional[TracebackType],
|
||||
) -> None:
|
||||
"""Shutdown the Processor from the context manager."""
|
||||
await self.shutdown()
|
||||
|
||||
|
||||
class SimpleUpdateProcessor(BaseUpdateProcessor):
|
||||
"""Instance of :class:`telegram.ext.BaseUpdateProcessor` that immediately awaits the
|
||||
|
||||
@@ -236,11 +236,13 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
|
||||
await self.application.persistence.refresh_bot_data(self.bot_data)
|
||||
if self.application.persistence.store_data.chat_data and self._chat_id is not None:
|
||||
await self.application.persistence.refresh_chat_data(
|
||||
chat_id=self._chat_id, chat_data=self.chat_data # type: ignore[arg-type]
|
||||
chat_id=self._chat_id,
|
||||
chat_data=self.chat_data, # type: ignore[arg-type]
|
||||
)
|
||||
if self.application.persistence.store_data.user_data and self._user_id is not None:
|
||||
await self.application.persistence.refresh_user_data(
|
||||
user_id=self._user_id, user_data=self.user_data # type: ignore[arg-type]
|
||||
user_id=self._user_id,
|
||||
user_data=self.user_data, # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
def drop_callback_data(self, callback_query: CallbackQuery) -> None:
|
||||
|
||||
@@ -227,14 +227,16 @@ class CallbackDataCache:
|
||||
# Built a new nested list of buttons by replacing the callback data if needed
|
||||
buttons = [
|
||||
[
|
||||
# We create a new button instead of replacing callback_data in case the
|
||||
# same object is used elsewhere
|
||||
InlineKeyboardButton(
|
||||
btn.text,
|
||||
callback_data=self.__put_button(btn.callback_data, keyboard_data),
|
||||
(
|
||||
# We create a new button instead of replacing callback_data in case the
|
||||
# same object is used elsewhere
|
||||
InlineKeyboardButton(
|
||||
btn.text,
|
||||
callback_data=self.__put_button(btn.callback_data, keyboard_data),
|
||||
)
|
||||
if btn.callback_data
|
||||
else btn
|
||||
)
|
||||
if btn.callback_data
|
||||
else btn
|
||||
for btn in column
|
||||
]
|
||||
for column in reply_markup.inline_keyboard
|
||||
|
||||
@@ -38,6 +38,7 @@ from typing import (
|
||||
from telegram import Update
|
||||
from telegram._utils.defaultvalue import DEFAULT_TRUE, DefaultValue
|
||||
from telegram._utils.logging import get_logger
|
||||
from telegram._utils.repr import build_repr_with_selected_attrs
|
||||
from telegram._utils.types import DVType
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.ext._application import ApplicationHandlerStop
|
||||
@@ -413,7 +414,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
):
|
||||
warn(
|
||||
f"Updates handled by {handler.__class__.__name__} only have information about "
|
||||
f"the user, so this handler won't ever be triggered if `per_chat=True`."
|
||||
"the user, so this handler won't ever be triggered if `per_chat=True`."
|
||||
f"{per_faq_link}",
|
||||
stacklevel=2,
|
||||
)
|
||||
@@ -440,6 +441,30 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Give a string representation of the ConversationHandler in the form
|
||||
``ConversationHandler[name=..., states={...}]``.
|
||||
|
||||
If there are more than 3 states, only the first 3 states are listed.
|
||||
|
||||
As this class doesn't implement :meth:`object.__str__`, the default implementation
|
||||
will be used, which is equivalent to :meth:`__repr__`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`
|
||||
"""
|
||||
truncation_threshold = 3
|
||||
states = dict(list(self.states.items())[:truncation_threshold])
|
||||
states_string = str(states)
|
||||
if len(self.states) > truncation_threshold:
|
||||
states_string = states_string[:-1] + ", ...}"
|
||||
|
||||
return build_repr_with_selected_attrs(
|
||||
self,
|
||||
name=self.name,
|
||||
states=states_string,
|
||||
)
|
||||
|
||||
@property
|
||||
def entry_points(self) -> List[BaseHandler[Update, CCT]]:
|
||||
"""List[:class:`telegram.ext.BaseHandler`]: A list of :obj:`BaseHandler` objects that can
|
||||
@@ -596,9 +621,16 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
self._conversations.update(current_conversations)
|
||||
# above might be partly overridden but that's okay since we warn about that in
|
||||
# add_handler
|
||||
self._conversations.update_no_track(
|
||||
await application.persistence.get_conversations(self.name)
|
||||
)
|
||||
stored_data = await application.persistence.get_conversations(self.name)
|
||||
self._conversations.update_no_track(stored_data)
|
||||
|
||||
# Since CH.END is stored as normal state, we need to properly parse it here in order to
|
||||
# actually end the conversation, i.e. delete the key from the _conversations dict
|
||||
# This also makes sure that these entries are deleted from the persisted data on the next
|
||||
# run of Application.update_persistence
|
||||
for key, state in stored_data.items():
|
||||
if state == self.END:
|
||||
self._update_state(new_state=self.END, key=key)
|
||||
|
||||
out = {self.name: self._conversations}
|
||||
|
||||
|
||||
+19
-22
@@ -104,6 +104,25 @@ class Defaults:
|
||||
if value is not None:
|
||||
self._api_defaults[kwarg] = value
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(
|
||||
(
|
||||
self._parse_mode,
|
||||
self._disable_notification,
|
||||
self._disable_web_page_preview,
|
||||
self._allow_sending_without_reply,
|
||||
self._quote,
|
||||
self._tzinfo,
|
||||
self._block,
|
||||
self._protect_content,
|
||||
)
|
||||
)
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, Defaults):
|
||||
return all(getattr(self, attr) == getattr(other, attr) for attr in self.__slots__)
|
||||
return False
|
||||
|
||||
@property
|
||||
def api_defaults(self) -> Dict[str, Any]: # skip-cq: PY-D0003
|
||||
return self._api_defaults
|
||||
@@ -220,25 +239,3 @@ class Defaults:
|
||||
raise AttributeError(
|
||||
"You can't assign a new value to protect_content after initialization."
|
||||
)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(
|
||||
(
|
||||
self._parse_mode,
|
||||
self._disable_notification,
|
||||
self._disable_web_page_preview,
|
||||
self._allow_sending_without_reply,
|
||||
self._quote,
|
||||
self._tzinfo,
|
||||
self._block,
|
||||
self._protect_content,
|
||||
)
|
||||
)
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, Defaults):
|
||||
return all(getattr(self, attr) == getattr(other, attr) for attr in self.__slots__)
|
||||
return False
|
||||
|
||||
def __ne__(self, other: object) -> bool:
|
||||
return not self == other
|
||||
|
||||
+82
-71
@@ -63,17 +63,14 @@ from telegram import (
|
||||
InlineKeyboardMarkup,
|
||||
InlineQueryResultsButton,
|
||||
InputMedia,
|
||||
InputSticker,
|
||||
Location,
|
||||
MaskPosition,
|
||||
MenuButton,
|
||||
Message,
|
||||
MessageId,
|
||||
PassportElementError,
|
||||
PhotoSize,
|
||||
Poll,
|
||||
SentWebAppMessage,
|
||||
ShippingOption,
|
||||
Sticker,
|
||||
StickerSet,
|
||||
Update,
|
||||
@@ -88,14 +85,8 @@ from telegram import (
|
||||
from telegram._utils.datetime import to_timestamp
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
|
||||
from telegram._utils.logging import get_logger
|
||||
from telegram._utils.types import (
|
||||
CorrectOptionID,
|
||||
DVInput,
|
||||
FileInput,
|
||||
JSONDict,
|
||||
ODVInput,
|
||||
ReplyMarkup,
|
||||
)
|
||||
from telegram._utils.repr import build_repr_with_selected_attrs
|
||||
from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup
|
||||
from telegram.ext._callbackdatacache import CallbackDataCache
|
||||
from telegram.ext._utils.types import RLARGS
|
||||
from telegram.request import BaseRequest
|
||||
@@ -108,8 +99,11 @@ if TYPE_CHECKING:
|
||||
InputMediaDocument,
|
||||
InputMediaPhoto,
|
||||
InputMediaVideo,
|
||||
InputSticker,
|
||||
LabeledPrice,
|
||||
MessageEntity,
|
||||
PassportElementError,
|
||||
ShippingOption,
|
||||
)
|
||||
from telegram.ext import BaseRateLimiter, Defaults
|
||||
|
||||
@@ -246,6 +240,17 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
self._callback_data_cache = CallbackDataCache(bot=self, maxsize=maxsize)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Give a string representation of the bot in the form ``ExtBot[token=...]``.
|
||||
|
||||
As this class doesn't implement :meth:`object.__str__`, the default implementation
|
||||
will be used, which is equivalent to :meth:`__repr__`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`
|
||||
"""
|
||||
return build_repr_with_selected_attrs(self, token=self.token)
|
||||
|
||||
@classmethod
|
||||
def _warn(
|
||||
cls, message: str, category: Type[Warning] = PTBUserWarning, stacklevel: int = 0
|
||||
@@ -544,7 +549,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
timeout: Optional[int] = None,
|
||||
allowed_updates: Optional[Sequence[str]] = None,
|
||||
*,
|
||||
read_timeout: float = 2,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -645,7 +650,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
message_id: int,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -674,9 +679,9 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
@@ -733,12 +738,12 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
async def add_sticker_to_set(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
name: str,
|
||||
sticker: Optional[InputSticker],
|
||||
sticker: Optional["InputSticker"],
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -845,7 +850,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
self,
|
||||
shipping_query_id: str,
|
||||
ok: bool,
|
||||
shipping_options: Optional[Sequence[ShippingOption]] = None,
|
||||
shipping_options: Optional[Sequence["ShippingOption"]] = None,
|
||||
error_message: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -914,7 +919,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
async def ban_chat_member(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
until_date: Optional[Union[int, datetime]] = None,
|
||||
revoke_messages: Optional[bool] = None,
|
||||
*,
|
||||
@@ -1047,16 +1052,16 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
async def create_new_sticker_set(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
name: str,
|
||||
title: str,
|
||||
stickers: Optional[Sequence[InputSticker]],
|
||||
stickers: Optional[Sequence["InputSticker"]],
|
||||
sticker_format: Optional[str],
|
||||
sticker_type: Optional[str] = None,
|
||||
needs_repainting: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -1329,7 +1334,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
message_id: Optional[int] = None,
|
||||
inline_message_id: Optional[str] = None,
|
||||
caption: Optional[str] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
*,
|
||||
@@ -1362,7 +1367,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
inline_message_id: Optional[str] = None,
|
||||
latitude: Optional[float] = None,
|
||||
longitude: Optional[float] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
horizontal_accuracy: Optional[float] = None,
|
||||
heading: Optional[int] = None,
|
||||
proximity_alert_radius: Optional[int] = None,
|
||||
@@ -1399,7 +1404,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
chat_id: Optional[Union[str, int]] = None,
|
||||
message_id: Optional[int] = None,
|
||||
inline_message_id: Optional[str] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -1455,7 +1460,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
inline_message_id: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -1506,7 +1511,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
chat_id: Union[int, str],
|
||||
from_chat_id: Union[str, int],
|
||||
message_id: int,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
*,
|
||||
@@ -1554,7 +1559,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
async def get_chat_member(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -1655,8 +1660,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
async def get_game_high_scores(
|
||||
self,
|
||||
user_id: Union[int, str],
|
||||
chat_id: Optional[Union[str, int]] = None,
|
||||
user_id: int,
|
||||
chat_id: Optional[int] = None,
|
||||
message_id: Optional[int] = None,
|
||||
inline_message_id: Optional[str] = None,
|
||||
*,
|
||||
@@ -1781,7 +1786,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
async def get_user_profile_photos(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
offset: Optional[int] = None,
|
||||
limit: Optional[int] = None,
|
||||
*,
|
||||
@@ -2032,7 +2037,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
async def promote_chat_member(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
can_change_info: Optional[bool] = None,
|
||||
can_post_messages: Optional[bool] = None,
|
||||
can_edit_messages: Optional[bool] = None,
|
||||
@@ -2045,6 +2050,9 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
can_manage_chat: Optional[bool] = None,
|
||||
can_manage_video_chats: Optional[bool] = None,
|
||||
can_manage_topics: Optional[bool] = None,
|
||||
can_post_stories: Optional[bool] = None,
|
||||
can_edit_stories: Optional[bool] = None,
|
||||
can_delete_stories: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -2068,6 +2076,9 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
can_manage_chat=can_manage_chat,
|
||||
can_manage_video_chats=can_manage_video_chats,
|
||||
can_manage_topics=can_manage_topics,
|
||||
can_post_stories=can_post_stories,
|
||||
can_edit_stories=can_edit_stories,
|
||||
can_delete_stories=can_delete_stories,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
@@ -2100,7 +2111,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
async def restrict_chat_member(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
permissions: ChatPermissions,
|
||||
until_date: Optional[Union[int, datetime]] = None,
|
||||
use_independent_chat_permissions: Optional[bool] = None,
|
||||
@@ -2156,7 +2167,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
height: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2168,7 +2179,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2207,7 +2218,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
performer: Optional[str] = None,
|
||||
title: Optional[str] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -2219,7 +2230,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2279,7 +2290,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
phone_number: Optional[str] = None,
|
||||
first_name: Optional[str] = None,
|
||||
last_name: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
vcard: Optional[str] = None,
|
||||
@@ -2354,7 +2365,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
chat_id: Union[int, str],
|
||||
document: Union[FileInput, "Document"],
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -2367,7 +2378,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2397,11 +2408,11 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
async def send_game(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
chat_id: int,
|
||||
game_short_name: str,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
@@ -2448,9 +2459,9 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
need_email: Optional[bool] = None,
|
||||
need_shipping_address: Optional[bool] = None,
|
||||
is_flexible: Optional[bool] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
provider_data: Optional[Union[str, object]] = None,
|
||||
send_phone_number_to_provider: Optional[bool] = None,
|
||||
send_email_to_provider: Optional[bool] = None,
|
||||
@@ -2508,7 +2519,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
chat_id: Union[int, str],
|
||||
latitude: Optional[float] = None,
|
||||
longitude: Optional[float] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
live_period: Optional[int] = None,
|
||||
@@ -2562,7 +2573,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
message_thread_id: Optional[int] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2596,7 +2607,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2634,7 +2645,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
chat_id: Union[int, str],
|
||||
photo: Union[FileInput, "PhotoSize"],
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -2646,7 +2657,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2733,7 +2744,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
sticker: Union[FileInput, "Sticker"],
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2742,7 +2753,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
emoji: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2773,7 +2784,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
title: Optional[str] = None,
|
||||
address: Optional[str] = None,
|
||||
foursquare_id: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
foursquare_type: Optional[str] = None,
|
||||
@@ -2821,7 +2832,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
video: Union[FileInput, "Video"],
|
||||
duration: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
width: Optional[int] = None,
|
||||
@@ -2837,7 +2848,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2875,7 +2886,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
video_note: Union[FileInput, "VideoNote"],
|
||||
duration: Optional[int] = None,
|
||||
length: Optional[int] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
@@ -2885,7 +2896,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2917,7 +2928,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
voice: Union[FileInput, "Voice"],
|
||||
duration: Optional[int] = None,
|
||||
caption: Optional[str] = None,
|
||||
disable_notification: DVInput[bool] = DEFAULT_NONE,
|
||||
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||
@@ -2928,7 +2939,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
*,
|
||||
filename: Optional[str] = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -2958,7 +2969,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
async def set_chat_administrator_custom_title(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
user_id: Union[int, str],
|
||||
user_id: int,
|
||||
custom_title: str,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -3053,7 +3064,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
photo: FileInput,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
@@ -3115,9 +3126,9 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
async def set_game_score(
|
||||
self,
|
||||
user_id: Union[int, str],
|
||||
user_id: int,
|
||||
score: int,
|
||||
chat_id: Optional[Union[str, int]] = None,
|
||||
chat_id: Optional[int] = None,
|
||||
message_id: Optional[int] = None,
|
||||
inline_message_id: Optional[str] = None,
|
||||
force: Optional[bool] = None,
|
||||
@@ -3193,8 +3204,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
async def set_passport_data_errors(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
errors: Sequence[PassportElementError],
|
||||
user_id: int,
|
||||
errors: Sequence["PassportElementError"],
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -3238,7 +3249,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
async def set_sticker_set_thumbnail(
|
||||
self,
|
||||
name: str,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -3296,7 +3307,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
chat_id: Optional[Union[str, int]] = None,
|
||||
message_id: Optional[int] = None,
|
||||
inline_message_id: Optional[str] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
reply_markup: Optional["InlineKeyboardMarkup"] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -3320,7 +3331,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
async def unban_chat_member(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
only_if_banned: Optional[bool] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -3449,12 +3460,12 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
|
||||
async def upload_sticker_file(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
user_id: int,
|
||||
sticker: Optional[FileInput],
|
||||
sticker_format: Optional[str],
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = 20,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
|
||||
+145
-73
@@ -31,6 +31,7 @@ try:
|
||||
except ImportError:
|
||||
APS_AVAILABLE = False
|
||||
|
||||
from telegram._utils.repr import build_repr_with_selected_attrs
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.ext._extbot import ExtBot
|
||||
@@ -75,6 +76,17 @@ class JobQueue(Generic[CCT]):
|
||||
Attributes:
|
||||
scheduler (:class:`apscheduler.schedulers.asyncio.AsyncIOScheduler`): The scheduler.
|
||||
|
||||
Warning:
|
||||
This scheduler is configured by :meth:`set_application`. Additional configuration
|
||||
settings can be made by users. However, calling
|
||||
:meth:`~apscheduler.schedulers.base.BaseScheduler.configure` will delete any
|
||||
previous configuration settings. Therefore, please make sure to pass the values
|
||||
returned by :attr:`scheduler_configuration` to the method call in addition to your
|
||||
custom values.
|
||||
Alternatively, you can also use methods like
|
||||
:meth:`~apscheduler.schedulers.base.BaseScheduler.add_jobstore` to avoid using
|
||||
:meth:`~apscheduler.schedulers.base.BaseScheduler.configure` altogether.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
Uses :class:`~apscheduler.schedulers.asyncio.AsyncIOScheduler` instead of
|
||||
:class:`~apscheduler.schedulers.background.BackgroundScheduler`
|
||||
@@ -93,9 +105,65 @@ class JobQueue(Generic[CCT]):
|
||||
|
||||
self._application: Optional[weakref.ReferenceType[Application]] = None
|
||||
self._executor = AsyncIOExecutor()
|
||||
self.scheduler: AsyncIOScheduler = AsyncIOScheduler(
|
||||
timezone=pytz.utc, executors={"default": self._executor}
|
||||
)
|
||||
self.scheduler: AsyncIOScheduler = AsyncIOScheduler(**self.scheduler_configuration)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Give a string representation of the JobQueue in the form ``JobQueue[application=...]``.
|
||||
|
||||
As this class doesn't implement :meth:`object.__str__`, the default implementation
|
||||
will be used, which is equivalent to :meth:`__repr__`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`
|
||||
"""
|
||||
return build_repr_with_selected_attrs(self, application=self.application)
|
||||
|
||||
@property
|
||||
def application(self) -> "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]":
|
||||
"""The application this JobQueue is associated with."""
|
||||
if self._application is None:
|
||||
raise RuntimeError("No application was set for this JobQueue.")
|
||||
application = self._application()
|
||||
if application is not None:
|
||||
return application
|
||||
raise RuntimeError("The application instance is no longer alive.")
|
||||
|
||||
@property
|
||||
def scheduler_configuration(self) -> JSONDict:
|
||||
"""Provides configuration values that are used by :class:`JobQueue` for :attr:`scheduler`.
|
||||
|
||||
Tip:
|
||||
Since calling
|
||||
:meth:`scheduler.configure() <apscheduler.schedulers.base.BaseScheduler.configure>`
|
||||
deletes any previous setting, please make sure to pass these values to the method call
|
||||
in addition to your custom values:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
scheduler.configure(..., **job_queue.scheduler_configuration)
|
||||
|
||||
Alternatively, you can also use methods like
|
||||
:meth:`~apscheduler.schedulers.base.BaseScheduler.add_jobstore` to avoid using
|
||||
:meth:`~apscheduler.schedulers.base.BaseScheduler.configure` altogether.
|
||||
|
||||
.. versionadded:: 20.7
|
||||
|
||||
Returns:
|
||||
Dict[:obj:`str`, :obj:`object`]: The configuration values as dictionary.
|
||||
|
||||
"""
|
||||
timezone: object = pytz.utc
|
||||
if (
|
||||
self._application
|
||||
and isinstance(self.application.bot, ExtBot)
|
||||
and self.application.bot.defaults
|
||||
):
|
||||
timezone = self.application.bot.defaults.tzinfo or pytz.utc
|
||||
|
||||
return {
|
||||
"timezone": timezone,
|
||||
"executors": {"default": self._executor},
|
||||
}
|
||||
|
||||
def _tz_now(self) -> datetime.datetime:
|
||||
return datetime.datetime.now(self.scheduler.timezone)
|
||||
@@ -107,14 +175,14 @@ class JobQueue(Generic[CCT]):
|
||||
@overload
|
||||
def _parse_time_input(
|
||||
self,
|
||||
time: Union[float, int, datetime.timedelta, datetime.datetime, datetime.time],
|
||||
time: Union[float, datetime.timedelta, datetime.datetime, datetime.time],
|
||||
shift_day: bool = False,
|
||||
) -> datetime.datetime:
|
||||
...
|
||||
|
||||
def _parse_time_input(
|
||||
self,
|
||||
time: Union[float, int, datetime.timedelta, datetime.datetime, datetime.time, None],
|
||||
time: Union[float, datetime.timedelta, datetime.datetime, datetime.time, None],
|
||||
shift_day: bool = False,
|
||||
) -> Optional[datetime.datetime]:
|
||||
if time is None:
|
||||
@@ -144,21 +212,7 @@ class JobQueue(Generic[CCT]):
|
||||
|
||||
"""
|
||||
self._application = weakref.ref(application)
|
||||
if isinstance(application.bot, ExtBot) and application.bot.defaults:
|
||||
self.scheduler.configure(
|
||||
timezone=application.bot.defaults.tzinfo or pytz.utc,
|
||||
executors={"default": self._executor},
|
||||
)
|
||||
|
||||
@property
|
||||
def application(self) -> "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]":
|
||||
"""The application this JobQueue is associated with."""
|
||||
if self._application is None:
|
||||
raise RuntimeError("No application was set for this JobQueue.")
|
||||
application = self._application()
|
||||
if application is not None:
|
||||
return application
|
||||
raise RuntimeError("The application instance is no longer alive.")
|
||||
self.scheduler.configure(**self.scheduler_configuration)
|
||||
|
||||
@staticmethod
|
||||
async def job_callback(job_queue: "JobQueue[CCT]", job: "Job[CCT]") -> None:
|
||||
@@ -766,6 +820,40 @@ class Job(Generic[CCT]):
|
||||
|
||||
self._job = cast("APSJob", None) # skipcq: PTC-W0052
|
||||
|
||||
def __getattr__(self, item: str) -> object:
|
||||
try:
|
||||
return getattr(self.job, item)
|
||||
except AttributeError as exc:
|
||||
raise AttributeError(
|
||||
f"Neither 'telegram.ext.Job' nor 'apscheduler.job.Job' has attribute '{item}'"
|
||||
) from exc
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, self.__class__):
|
||||
return self.id == other.id
|
||||
return False
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(self.id)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Give a string representation of the job in the form
|
||||
``Job[id=..., name=..., callback=..., trigger=...]``.
|
||||
|
||||
As this class doesn't implement :meth:`object.__str__`, the default implementation
|
||||
will be used, which is equivalent to :meth:`__repr__`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`
|
||||
"""
|
||||
return build_repr_with_selected_attrs(
|
||||
self,
|
||||
id=self.job.id,
|
||||
name=self.name,
|
||||
callback=self.callback.__name__,
|
||||
trigger=self.job.trigger,
|
||||
)
|
||||
|
||||
@property
|
||||
def job(self) -> "APSJob":
|
||||
""":class:`apscheduler.job.Job`: The APS Job this job is a wrapper for.
|
||||
@@ -775,46 +863,6 @@ class Job(Generic[CCT]):
|
||||
"""
|
||||
return self._job
|
||||
|
||||
async def run(
|
||||
self, application: "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]"
|
||||
) -> None:
|
||||
"""Executes the callback function independently of the jobs schedule. Also calls
|
||||
:meth:`telegram.ext.Application.update_persistence`.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
Calls :meth:`telegram.ext.Application.update_persistence`.
|
||||
|
||||
Args:
|
||||
application (:class:`telegram.ext.Application`): The application this job is associated
|
||||
with.
|
||||
"""
|
||||
# We shield the task such that the job isn't cancelled mid-run
|
||||
await asyncio.shield(self._run(application))
|
||||
|
||||
async def _run(
|
||||
self, application: "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]"
|
||||
) -> None:
|
||||
try:
|
||||
context = application.context_types.context.from_job(self, application)
|
||||
await context.refresh_data()
|
||||
await self.callback(context)
|
||||
except Exception as exc:
|
||||
await application.create_task(
|
||||
application.process_error(None, exc, job=self),
|
||||
name=f"Job:{self.id}:run:process_error",
|
||||
)
|
||||
finally:
|
||||
# This is internal logic of application - let's keep it private for now
|
||||
application._mark_for_persistence_update(job=self) # pylint: disable=protected-access
|
||||
|
||||
def schedule_removal(self) -> None:
|
||||
"""
|
||||
Schedules this job for removal from the :class:`JobQueue`. It will be removed without
|
||||
executing its callback function again.
|
||||
"""
|
||||
self.job.remove()
|
||||
self._removed = True
|
||||
|
||||
@property
|
||||
def removed(self) -> bool:
|
||||
""":obj:`bool`: Whether this job is due to be removed."""
|
||||
@@ -867,18 +915,42 @@ class Job(Generic[CCT]):
|
||||
ext_job._job = aps_job # pylint: disable=protected-access
|
||||
return ext_job
|
||||
|
||||
def __getattr__(self, item: str) -> object:
|
||||
async def run(
|
||||
self, application: "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]"
|
||||
) -> None:
|
||||
"""Executes the callback function independently of the jobs schedule. Also calls
|
||||
:meth:`telegram.ext.Application.update_persistence`.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
Calls :meth:`telegram.ext.Application.update_persistence`.
|
||||
|
||||
Args:
|
||||
application (:class:`telegram.ext.Application`): The application this job is associated
|
||||
with.
|
||||
"""
|
||||
# We shield the task such that the job isn't cancelled mid-run
|
||||
await asyncio.shield(self._run(application))
|
||||
|
||||
async def _run(
|
||||
self, application: "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]"
|
||||
) -> None:
|
||||
try:
|
||||
return getattr(self.job, item)
|
||||
except AttributeError as exc:
|
||||
raise AttributeError(
|
||||
f"Neither 'telegram.ext.Job' nor 'apscheduler.job.Job' has attribute '{item}'"
|
||||
) from exc
|
||||
context = application.context_types.context.from_job(self, application)
|
||||
await context.refresh_data()
|
||||
await self.callback(context)
|
||||
except Exception as exc:
|
||||
await application.create_task(
|
||||
application.process_error(None, exc, job=self),
|
||||
name=f"Job:{self.id}:run:process_error",
|
||||
)
|
||||
finally:
|
||||
# This is internal logic of application - let's keep it private for now
|
||||
application._mark_for_persistence_update(job=self) # pylint: disable=protected-access
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, self.__class__):
|
||||
return self.id == other.id
|
||||
return False
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(self.id)
|
||||
def schedule_removal(self) -> None:
|
||||
"""
|
||||
Schedules this job for removal from the :class:`JobQueue`. It will be removed without
|
||||
executing its callback function again.
|
||||
"""
|
||||
self.job.remove()
|
||||
self._removed = True
|
||||
|
||||
@@ -492,7 +492,7 @@ class PicklePersistence(BasePersistence[UD, CD, BD]):
|
||||
"""
|
||||
if self.chat_data is None:
|
||||
return
|
||||
self.chat_data.pop(chat_id, None) # type: ignore[arg-type]
|
||||
self.chat_data.pop(chat_id, None)
|
||||
|
||||
if not self.on_flush:
|
||||
if not self.single_file:
|
||||
@@ -511,7 +511,7 @@ class PicklePersistence(BasePersistence[UD, CD, BD]):
|
||||
"""
|
||||
if self.user_data is None:
|
||||
return
|
||||
self.user_data.pop(user_id, None) # type: ignore[arg-type]
|
||||
self.user_data.pop(user_id, None)
|
||||
|
||||
if not self.on_flush:
|
||||
if not self.single_file:
|
||||
|
||||
+93
-33
@@ -37,6 +37,7 @@ from typing import (
|
||||
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.logging import get_logger
|
||||
from telegram._utils.repr import build_repr_with_selected_attrs
|
||||
from telegram._utils.types import ODVInput
|
||||
from telegram.error import InvalidToken, RetryAfter, TelegramError, TimedOut
|
||||
|
||||
@@ -77,6 +78,8 @@ class Updater(AsyncContextManager["Updater"]):
|
||||
finally:
|
||||
await updater.shutdown()
|
||||
|
||||
.. seealso:: :meth:`__aenter__` and :meth:`__aexit__`.
|
||||
|
||||
.. seealso:: :wiki:`Architecture Overview <Architecture>`,
|
||||
:wiki:`Builder Pattern <Builder-Pattern>`
|
||||
|
||||
@@ -124,6 +127,46 @@ class Updater(AsyncContextManager["Updater"]):
|
||||
self.__polling_task: Optional[asyncio.Task] = None
|
||||
self.__polling_cleanup_cb: Optional[Callable[[], Coroutine[Any, Any, None]]] = None
|
||||
|
||||
async def __aenter__(self: _UpdaterType) -> _UpdaterType: # noqa: PYI019
|
||||
"""
|
||||
|async_context_manager| :meth:`initializes <initialize>` the Updater.
|
||||
|
||||
Returns:
|
||||
The initialized Updater instance.
|
||||
|
||||
Raises:
|
||||
:exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown`
|
||||
is called in this case.
|
||||
"""
|
||||
try:
|
||||
await self.initialize()
|
||||
return self
|
||||
except Exception as exc:
|
||||
await self.shutdown()
|
||||
raise exc
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[Type[BaseException]],
|
||||
exc_val: Optional[BaseException],
|
||||
exc_tb: Optional[TracebackType],
|
||||
) -> None:
|
||||
"""|async_context_manager| :meth:`shuts down <shutdown>` the Updater."""
|
||||
# Make sure not to return `True` so that exceptions are not suppressed
|
||||
# https://docs.python.org/3/reference/datamodel.html?#object.__aexit__
|
||||
await self.shutdown()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Give a string representation of the updater in the form ``Updater[bot=...]``.
|
||||
|
||||
As this class doesn't implement :meth:`object.__str__`, the default implementation
|
||||
will be used, which is equivalent to :meth:`__repr__`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`
|
||||
"""
|
||||
return build_repr_with_selected_attrs(self, bot=self.bot)
|
||||
|
||||
@property
|
||||
def running(self) -> bool:
|
||||
return self._running
|
||||
@@ -163,32 +206,12 @@ class Updater(AsyncContextManager["Updater"]):
|
||||
self._initialized = False
|
||||
_LOGGER.debug("Shut down of Updater complete")
|
||||
|
||||
async def __aenter__(self: _UpdaterType) -> _UpdaterType:
|
||||
"""Simple context manager which initializes the Updater."""
|
||||
try:
|
||||
await self.initialize()
|
||||
return self
|
||||
except Exception as exc:
|
||||
await self.shutdown()
|
||||
raise exc
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[Type[BaseException]],
|
||||
exc_val: Optional[BaseException],
|
||||
exc_tb: Optional[TracebackType],
|
||||
) -> None:
|
||||
"""Shutdown the Updater from the context manager."""
|
||||
# Make sure not to return `True` so that exceptions are not suppressed
|
||||
# https://docs.python.org/3/reference/datamodel.html?#object.__aexit__
|
||||
await self.shutdown()
|
||||
|
||||
async def start_polling(
|
||||
self,
|
||||
poll_interval: float = 0.0,
|
||||
timeout: int = 10,
|
||||
bootstrap_retries: int = -1,
|
||||
read_timeout: float = 2,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
@@ -213,16 +236,40 @@ class Updater(AsyncContextManager["Updater"]):
|
||||
* 0 - no retries
|
||||
* > 0 - retry up to X times
|
||||
read_timeout (:obj:`float`, optional): Value to pass to
|
||||
:paramref:`telegram.Bot.get_updates.read_timeout`. Defaults to ``2``.
|
||||
:paramref:`telegram.Bot.get_updates.read_timeout`. Defaults to
|
||||
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
|
||||
|
||||
.. versionchanged:: 20.7
|
||||
Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE` instead of
|
||||
``2``.
|
||||
.. deprecated:: 20.7
|
||||
Deprecated in favor of setting the timeout via
|
||||
:meth:`telegram.ext.ApplicationBuilder.get_updates_read_timeout` or
|
||||
:paramref:`telegram.Bot.get_updates_request`.
|
||||
write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
|
||||
:paramref:`telegram.Bot.get_updates.write_timeout`. Defaults to
|
||||
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
|
||||
|
||||
.. deprecated:: 20.7
|
||||
Deprecated in favor of setting the timeout via
|
||||
:meth:`telegram.ext.ApplicationBuilder.get_updates_write_timeout` or
|
||||
:paramref:`telegram.Bot.get_updates_request`.
|
||||
connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
|
||||
:paramref:`telegram.Bot.get_updates.connect_timeout`. Defaults to
|
||||
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
|
||||
|
||||
.. deprecated:: 20.7
|
||||
Deprecated in favor of setting the timeout via
|
||||
:meth:`telegram.ext.ApplicationBuilder.get_updates_connect_timeout` or
|
||||
:paramref:`telegram.Bot.get_updates_request`.
|
||||
pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
|
||||
:paramref:`telegram.Bot.get_updates.pool_timeout`. Defaults to
|
||||
:attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
|
||||
|
||||
.. deprecated:: 20.7
|
||||
Deprecated in favor of setting the timeout via
|
||||
:meth:`telegram.ext.ApplicationBuilder.get_updates_pool_timeout` or
|
||||
:paramref:`telegram.Bot.get_updates_request`.
|
||||
allowed_updates (List[:obj:`str`], optional): Passed to
|
||||
:meth:`telegram.Bot.get_updates`.
|
||||
drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on
|
||||
@@ -248,6 +295,10 @@ class Updater(AsyncContextManager["Updater"]):
|
||||
:exc:`RuntimeError`: If the updater is already running or was not initialized.
|
||||
|
||||
"""
|
||||
# We refrain from issuing deprecation warnings for the timeout parameters here, as we
|
||||
# already issue them in `Application`. This means that there are no warnings when using
|
||||
# `Updater` without `Application`, but this is a rather special use case.
|
||||
|
||||
if error_callback and asyncio.iscoroutinefunction(error_callback):
|
||||
raise TypeError(
|
||||
"The `error_callback` must not be a coroutine function! Use an ordinary function "
|
||||
@@ -293,7 +344,7 @@ class Updater(AsyncContextManager["Updater"]):
|
||||
self,
|
||||
poll_interval: float,
|
||||
timeout: int,
|
||||
read_timeout: float,
|
||||
read_timeout: ODVInput[float],
|
||||
write_timeout: ODVInput[float],
|
||||
connect_timeout: ODVInput[float],
|
||||
pool_timeout: ODVInput[float],
|
||||
@@ -378,16 +429,25 @@ class Updater(AsyncContextManager["Updater"]):
|
||||
_LOGGER.debug(
|
||||
"Calling `get_updates` one more time to mark all fetched updates as read."
|
||||
)
|
||||
await self.bot.get_updates(
|
||||
offset=self._last_update_id,
|
||||
# We don't want to do long polling here!
|
||||
timeout=0,
|
||||
read_timeout=read_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
write_timeout=write_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
allowed_updates=allowed_updates,
|
||||
)
|
||||
try:
|
||||
await self.bot.get_updates(
|
||||
offset=self._last_update_id,
|
||||
# We don't want to do long polling here!
|
||||
timeout=0,
|
||||
read_timeout=read_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
write_timeout=write_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
allowed_updates=allowed_updates,
|
||||
)
|
||||
except TelegramError as exc:
|
||||
_LOGGER.error(
|
||||
"Error while calling `get_updates` one more time to mark all fetched updates "
|
||||
"as read: %s. Suppressing error to ensure graceful shutdown. When polling for "
|
||||
"updates is restarted, updates may be fetched again. Please adjust timeouts "
|
||||
"via `ApplicationBuilder` or the parameter `get_updates_request` of `Bot`.",
|
||||
exc_info=exc,
|
||||
)
|
||||
|
||||
self.__polling_cleanup_cb = _get_updates_cleanup
|
||||
|
||||
|
||||
@@ -54,6 +54,14 @@ class TrackingDict(UserDict, Generic[_KT, _VT]):
|
||||
super().__init__()
|
||||
self._write_access_keys: Set[_KT] = set()
|
||||
|
||||
def __setitem__(self, key: _KT, value: _VT) -> None:
|
||||
self.__track_write(key)
|
||||
super().__setitem__(key, value)
|
||||
|
||||
def __delitem__(self, key: _KT) -> None:
|
||||
self.__track_write(key)
|
||||
super().__delitem__(key)
|
||||
|
||||
def __track_write(self, key: Union[_KT, Set[_KT]]) -> None:
|
||||
if isinstance(key, set):
|
||||
self._write_access_keys |= key
|
||||
@@ -83,14 +91,6 @@ class TrackingDict(UserDict, Generic[_KT, _VT]):
|
||||
|
||||
# Override methods to track access
|
||||
|
||||
def __setitem__(self, key: _KT, value: _VT) -> None:
|
||||
self.__track_write(key)
|
||||
super().__setitem__(key, value)
|
||||
|
||||
def __delitem__(self, key: _KT) -> None:
|
||||
self.__track_write(key)
|
||||
super().__delitem__(key)
|
||||
|
||||
def update_no_track(self, mapping: Mapping[_KT, _VT]) -> None:
|
||||
"""Like ``update``, but doesn't count towards write access."""
|
||||
for key, value in mapping.items():
|
||||
@@ -99,7 +99,9 @@ class TrackingDict(UserDict, Generic[_KT, _VT]):
|
||||
# Mypy seems a bit inconsistent about what it wants as types for `default` and return value
|
||||
# so we just ignore a bit
|
||||
def pop( # type: ignore[override]
|
||||
self, key: _KT, default: _VT = DEFAULT_NONE # type: ignore[assignment]
|
||||
self,
|
||||
key: _KT,
|
||||
default: _VT = DEFAULT_NONE, # type: ignore[assignment]
|
||||
) -> _VT:
|
||||
if key in self:
|
||||
self.__track_write(key)
|
||||
|
||||
+103
-35
@@ -66,6 +66,7 @@ __all__ = (
|
||||
"LOCATION",
|
||||
"Language",
|
||||
"MessageFilter",
|
||||
"Mention",
|
||||
"PASSPORT_DATA",
|
||||
"PHOTO",
|
||||
"POLL",
|
||||
@@ -91,7 +92,6 @@ __all__ = (
|
||||
"VOICE",
|
||||
"ViaBot",
|
||||
)
|
||||
|
||||
import mimetypes
|
||||
import re
|
||||
from abc import ABC, abstractmethod
|
||||
@@ -99,6 +99,7 @@ from typing import (
|
||||
Collection,
|
||||
Dict,
|
||||
FrozenSet,
|
||||
Iterable,
|
||||
List,
|
||||
Match,
|
||||
NoReturn,
|
||||
@@ -182,6 +183,39 @@ class BaseFilter:
|
||||
self._name = self.__class__.__name__ if name is None else name
|
||||
self._data_filter = data_filter
|
||||
|
||||
def __and__(self, other: "BaseFilter") -> "BaseFilter":
|
||||
return _MergedFilter(self, and_filter=other)
|
||||
|
||||
def __or__(self, other: "BaseFilter") -> "BaseFilter":
|
||||
return _MergedFilter(self, or_filter=other)
|
||||
|
||||
def __xor__(self, other: "BaseFilter") -> "BaseFilter":
|
||||
return _XORFilter(self, other)
|
||||
|
||||
def __invert__(self) -> "BaseFilter":
|
||||
return _InvertedFilter(self)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def data_filter(self) -> bool:
|
||||
""":obj:`bool`: Whether this filter is a data filter."""
|
||||
return self._data_filter
|
||||
|
||||
@data_filter.setter
|
||||
def data_filter(self, value: bool) -> None:
|
||||
self._data_filter = value
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
""":obj:`str`: Name for this filter."""
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, name: str) -> None:
|
||||
self._name = name
|
||||
|
||||
def check_update( # skipcq: PYL-R0201
|
||||
self, update: Update
|
||||
) -> Optional[Union[bool, FilterDataDict]]:
|
||||
@@ -205,39 +239,6 @@ class BaseFilter:
|
||||
return True
|
||||
return False
|
||||
|
||||
def __and__(self, other: "BaseFilter") -> "BaseFilter":
|
||||
return _MergedFilter(self, and_filter=other)
|
||||
|
||||
def __or__(self, other: "BaseFilter") -> "BaseFilter":
|
||||
return _MergedFilter(self, or_filter=other)
|
||||
|
||||
def __xor__(self, other: "BaseFilter") -> "BaseFilter":
|
||||
return _XORFilter(self, other)
|
||||
|
||||
def __invert__(self) -> "BaseFilter":
|
||||
return _InvertedFilter(self)
|
||||
|
||||
@property
|
||||
def data_filter(self) -> bool:
|
||||
""":obj:`bool`: Whether this filter is a data filter."""
|
||||
return self._data_filter
|
||||
|
||||
@data_filter.setter
|
||||
def data_filter(self, value: bool) -> None:
|
||||
self._data_filter = value
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
""":obj:`str`: Name for this filter."""
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, name: str) -> None:
|
||||
self._name = name
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.name
|
||||
|
||||
|
||||
class MessageFilter(BaseFilter):
|
||||
"""Base class for all Message Filters. In contrast to :class:`UpdateFilter`, the object passed
|
||||
@@ -763,7 +764,7 @@ class _ChatUserBaseFilter(MessageFilter, ABC):
|
||||
def name(self) -> str:
|
||||
return (
|
||||
f"filters.{self.__class__.__name__}("
|
||||
f'{", ".join(str(s) for s in (self.usernames or self.chat_ids))})'
|
||||
f"{', '.join(str(s) for s in (self.usernames or self.chat_ids))})"
|
||||
)
|
||||
|
||||
@name.setter
|
||||
@@ -1521,6 +1522,73 @@ LOCATION = _Location(name="filters.LOCATION")
|
||||
"""Messages that contain :attr:`telegram.Message.location`."""
|
||||
|
||||
|
||||
class Mention(MessageFilter):
|
||||
"""Messages containing mentions of specified users or chats.
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
|
||||
MessageHandler(filters.Mention("username"), callback)
|
||||
MessageHandler(filters.Mention(["@username", 123456]), callback)
|
||||
|
||||
.. versionadded:: 20.7
|
||||
|
||||
Args:
|
||||
mentions (:obj:`int` | :obj:`str` | :class:`telegram.User` | Collection[:obj:`int` | \
|
||||
:obj:`str` | :class:`telegram.User`]):
|
||||
Specifies the users and chats to filter for. Messages that do not mention at least one
|
||||
of the specified users or chats will not be handled. Leading ``'@'`` s in usernames
|
||||
will be discarded.
|
||||
"""
|
||||
|
||||
__slots__ = ("_mentions",)
|
||||
|
||||
def __init__(self, mentions: SCT[Union[int, str, TGUser]]):
|
||||
super().__init__(name=f"filters.Mention({mentions})")
|
||||
if isinstance(mentions, Iterable) and not isinstance(mentions, str):
|
||||
self._mentions = {self._fix_mention_username(mention) for mention in mentions}
|
||||
else:
|
||||
self._mentions = {self._fix_mention_username(mentions)}
|
||||
|
||||
@staticmethod
|
||||
def _fix_mention_username(mention: Union[int, str, TGUser]) -> Union[int, str, TGUser]:
|
||||
if not isinstance(mention, str):
|
||||
return mention
|
||||
return mention.lstrip("@")
|
||||
|
||||
@classmethod
|
||||
def _check_mention(cls, message: Message, mention: Union[int, str, TGUser]) -> bool:
|
||||
if not message.entities:
|
||||
return False
|
||||
|
||||
entity_texts = message.parse_entities(
|
||||
types=[MessageEntity.MENTION, MessageEntity.TEXT_MENTION]
|
||||
)
|
||||
|
||||
if isinstance(mention, TGUser):
|
||||
return any(
|
||||
mention.id == entity.user.id
|
||||
or mention.username == entity.user.username
|
||||
or mention.username == cls._fix_mention_username(entity_texts[entity])
|
||||
for entity in message.entities
|
||||
if entity.user
|
||||
) or any(
|
||||
mention.username == cls._fix_mention_username(entity_text)
|
||||
for entity_text in entity_texts.values()
|
||||
)
|
||||
if isinstance(mention, int):
|
||||
return bool(
|
||||
any(mention == entity.user.id for entity in message.entities if entity.user)
|
||||
)
|
||||
return any(
|
||||
mention == cls._fix_mention_username(entity_text)
|
||||
for entity_text in entity_texts.values()
|
||||
)
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return any(self._check_mention(message, mention) for mention in self._mentions)
|
||||
|
||||
|
||||
class _PassportData(MessageFilter):
|
||||
__slots__ = ()
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ from telegram._utils.defaultvalue import DEFAULT_NONE as _DEFAULT_NONE
|
||||
from telegram._utils.defaultvalue import DefaultValue
|
||||
from telegram._utils.logging import get_logger
|
||||
from telegram._utils.types import JSONDict, ODVInput
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram._version import __version__ as ptb_ver
|
||||
from telegram.error import (
|
||||
BadRequest,
|
||||
@@ -39,6 +40,7 @@ from telegram.error import (
|
||||
TelegramError,
|
||||
)
|
||||
from telegram.request._requestdata import RequestData
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
RT = TypeVar("RT", bound="BaseRequest")
|
||||
|
||||
@@ -70,6 +72,8 @@ class BaseRequest(
|
||||
finally:
|
||||
await request_object.shutdown()
|
||||
|
||||
.. seealso:: :meth:`__aenter__` and :meth:`__aexit__`.
|
||||
|
||||
Tip:
|
||||
JSON encoding and decoding is done with the standard library's :mod:`json` by default.
|
||||
To use a custom library for this, you can override :meth:`parse_json_payload` and implement
|
||||
@@ -99,6 +103,15 @@ class BaseRequest(
|
||||
"""
|
||||
|
||||
async def __aenter__(self: RT) -> RT:
|
||||
"""|async_context_manager| :meth:`initializes <initialize>` the Request.
|
||||
|
||||
Returns:
|
||||
The initialized Request instance.
|
||||
|
||||
Raises:
|
||||
:exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown`
|
||||
is called in this case.
|
||||
"""
|
||||
try:
|
||||
await self.initialize()
|
||||
return self
|
||||
@@ -112,10 +125,29 @@ class BaseRequest(
|
||||
exc_val: Optional[BaseException],
|
||||
exc_tb: Optional[TracebackType],
|
||||
) -> None:
|
||||
"""|async_context_manager| :meth:`shuts down <shutdown>` the Request."""
|
||||
# Make sure not to return `True` so that exceptions are not suppressed
|
||||
# https://docs.python.org/3/reference/datamodel.html?#object.__aexit__
|
||||
await self.shutdown()
|
||||
|
||||
@property
|
||||
def read_timeout(self) -> Optional[float]:
|
||||
"""This property must return the default read timeout in seconds used by this class.
|
||||
More precisely, the returned value should be the one used when
|
||||
:paramref:`post.read_timeout` of :meth:post` is not passed/equal to :attr:`DEFAULT_NONE`.
|
||||
|
||||
.. versionadded:: 20.7
|
||||
|
||||
Warning:
|
||||
For now this property does not need to be implemented by subclasses and will raise
|
||||
:exc:`NotImplementedError` if accessed without being overridden. However, in future
|
||||
versions, this property will be abstract and must be implemented by subclasses.
|
||||
|
||||
Returns:
|
||||
:obj:`float` | :obj:`None`: The read timeout in seconds.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
async def initialize(self) -> None:
|
||||
"""Initialize resources used by this class. Must be implemented by a subclass."""
|
||||
@@ -271,8 +303,28 @@ class BaseRequest(
|
||||
TelegramError
|
||||
|
||||
"""
|
||||
# TGs response also has the fields 'ok' and 'error_code'.
|
||||
# However, we rather rely on the HTTP status code for now.
|
||||
# Import needs to be here since HTTPXRequest is a subclass of BaseRequest
|
||||
from telegram.request import HTTPXRequest # pylint: disable=import-outside-toplevel
|
||||
|
||||
# 20 is the documented default value for all the media related bot methods and custom
|
||||
# implementations of BaseRequest may explicitly rely on that. Hence, we follow the
|
||||
# standard deprecation policy and deprecate starting with version 20.7.
|
||||
# For our own implementation HTTPXRequest, we can handle that ourselves, so we skip the
|
||||
# warning in that case.
|
||||
has_files = request_data and request_data.multipart_data
|
||||
if (
|
||||
has_files
|
||||
and not isinstance(self, HTTPXRequest)
|
||||
and isinstance(write_timeout, DefaultValue)
|
||||
):
|
||||
warn(
|
||||
f"The `write_timeout` parameter passed to {self.__class__.__name__}.do_request "
|
||||
"will default to `BaseRequest.DEFAULT_NONE` instead of 20 in future versions "
|
||||
"for *all* methods of the `Bot` class, including methods sending media.",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel=3,
|
||||
)
|
||||
write_timeout = 20
|
||||
|
||||
try:
|
||||
code, payload = await self.do_request(
|
||||
@@ -301,6 +353,8 @@ class BaseRequest(
|
||||
# In some special cases, we can raise more informative exceptions:
|
||||
# see https://core.telegram.org/bots/api#responseparameters and
|
||||
# https://core.telegram.org/bots/api#making-requests
|
||||
# TGs response also has the fields 'ok' and 'error_code'.
|
||||
# However, we rather rely on the HTTP status code for now.
|
||||
parameters = response_data.get("parameters")
|
||||
if parameters:
|
||||
migrate_to_chat_id = parameters.get("migrate_to_chat_id")
|
||||
|
||||
@@ -17,16 +17,18 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains methods to make POST and GET requests using the httpx library."""
|
||||
from typing import Optional, Tuple
|
||||
from typing import Collection, Optional, Tuple, Union
|
||||
|
||||
import httpx
|
||||
|
||||
from telegram._utils.defaultvalue import DefaultValue
|
||||
from telegram._utils.logging import get_logger
|
||||
from telegram._utils.types import HTTPVersion, ODVInput
|
||||
from telegram._utils.types import HTTPVersion, ODVInput, SocketOpt
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.error import NetworkError, TimedOut
|
||||
from telegram.request._baserequest import BaseRequest
|
||||
from telegram.request._requestdata import RequestData
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
# Note to future devs:
|
||||
# Proxies are currently only tested manually. The httpx development docs have a nice guide on that:
|
||||
@@ -49,17 +51,10 @@ class HTTPXRequest(BaseRequest):
|
||||
Note:
|
||||
Independent of the value, one additional connection will be reserved for
|
||||
:meth:`telegram.Bot.get_updates`.
|
||||
proxy_url (:obj:`str`, optional): The URL to the proxy server. For example
|
||||
``'http://127.0.0.1:3128'`` or ``'socks5://127.0.0.1:3128'``. Defaults to :obj:`None`.
|
||||
proxy_url (:obj:`str`, optional): Legacy name for :paramref:`proxy`, kept for backward
|
||||
compatibility. Defaults to :obj:`None`.
|
||||
|
||||
Note:
|
||||
* The proxy URL can also be set via the environment variables ``HTTPS_PROXY`` or
|
||||
``ALL_PROXY``. See `the docs of httpx`_ for more info.
|
||||
* For Socks5 support, additional dependencies are required. Make sure to install
|
||||
PTB via :command:`pip install "python-telegram-bot[socks]"` in this case.
|
||||
* Socks5 proxies can not be set via environment variables.
|
||||
|
||||
.. _the docs of httpx: https://www.python-httpx.org/environment_variables/#proxies
|
||||
.. deprecated:: 20.7
|
||||
read_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum
|
||||
amount of time (in seconds) to wait for a response from Telegram's server.
|
||||
This value is used unless a different value is passed to :meth:`do_request`.
|
||||
@@ -91,6 +86,32 @@ class HTTPXRequest(BaseRequest):
|
||||
|
||||
.. versionchanged:: 20.5
|
||||
Accept ``"2"`` as a valid value.
|
||||
socket_options (Collection[:obj:`tuple`], optional): Socket options to be passed to the
|
||||
underlying `library \
|
||||
<https://www.encode.io/httpcore/async/#httpcore.AsyncConnectionPool.__init__>`_.
|
||||
|
||||
Note:
|
||||
The values accepted by this parameter depend on the operating system.
|
||||
This is a low-level parameter and should only be used if you are familiar with
|
||||
these concepts.
|
||||
|
||||
.. versionadded:: 20.7
|
||||
proxy (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``, optional): The URL to a proxy server,
|
||||
a ``httpx.Proxy`` object or a ``httpx.URL`` object. For example
|
||||
``'http://127.0.0.1:3128'`` or ``'socks5://127.0.0.1:3128'``. Defaults to :obj:`None`.
|
||||
|
||||
Note:
|
||||
* The proxy URL can also be set via the environment variables ``HTTPS_PROXY`` or
|
||||
``ALL_PROXY``. See `the docs of httpx`_ for more info.
|
||||
* HTTPS proxies can be configured by passing a ``httpx.Proxy`` object with
|
||||
a corresponding ``ssl_context``.
|
||||
* For Socks5 support, additional dependencies are required. Make sure to install
|
||||
PTB via :command:`pip install "python-telegram-bot[socks]"` in this case.
|
||||
* Socks5 proxies can not be set via environment variables.
|
||||
|
||||
.. _the docs of httpx: https://www.python-httpx.org/environment_variables/#proxies
|
||||
|
||||
.. versionadded:: 20.7
|
||||
|
||||
"""
|
||||
|
||||
@@ -99,13 +120,27 @@ class HTTPXRequest(BaseRequest):
|
||||
def __init__(
|
||||
self,
|
||||
connection_pool_size: int = 1,
|
||||
proxy_url: Optional[str] = None,
|
||||
proxy_url: Optional[Union[str, httpx.Proxy, httpx.URL]] = None,
|
||||
read_timeout: Optional[float] = 5.0,
|
||||
write_timeout: Optional[float] = 5.0,
|
||||
connect_timeout: Optional[float] = 5.0,
|
||||
pool_timeout: Optional[float] = 1.0,
|
||||
http_version: HTTPVersion = "1.1",
|
||||
socket_options: Optional[Collection[SocketOpt]] = None,
|
||||
proxy: Optional[Union[str, httpx.Proxy, httpx.URL]] = None,
|
||||
):
|
||||
if proxy_url is not None and proxy is not None:
|
||||
raise ValueError("The parameters `proxy_url` and `proxy` are mutually exclusive.")
|
||||
|
||||
if proxy_url is not None:
|
||||
proxy = proxy_url
|
||||
warn(
|
||||
"The parameter `proxy_url` is deprecated since version 20.7. Use `proxy` "
|
||||
"instead.",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
self._http_version = http_version
|
||||
timeout = httpx.Timeout(
|
||||
connect=connect_timeout,
|
||||
@@ -122,16 +157,21 @@ class HTTPXRequest(BaseRequest):
|
||||
raise ValueError("`http_version` must be either '1.1', '2.0' or '2'.")
|
||||
|
||||
http1 = http_version == "1.1"
|
||||
|
||||
# See https://github.com/python-telegram-bot/python-telegram-bot/pull/3542
|
||||
# for why we need to use `dict()` here.
|
||||
self._client_kwargs = dict( # pylint: disable=use-dict-literal # noqa: C408
|
||||
timeout=timeout,
|
||||
proxies=proxy_url,
|
||||
limits=limits,
|
||||
http1=http1,
|
||||
http2=not http1,
|
||||
http_kwargs = {"http1": http1, "http2": not http1}
|
||||
transport = (
|
||||
httpx.AsyncHTTPTransport(
|
||||
socket_options=socket_options,
|
||||
)
|
||||
if socket_options
|
||||
else None
|
||||
)
|
||||
self._client_kwargs = {
|
||||
"timeout": timeout,
|
||||
"proxies": proxy,
|
||||
"limits": limits,
|
||||
"transport": transport,
|
||||
**http_kwargs,
|
||||
}
|
||||
|
||||
try:
|
||||
self._client = self._build_client()
|
||||
@@ -158,6 +198,16 @@ class HTTPXRequest(BaseRequest):
|
||||
"""
|
||||
return self._http_version
|
||||
|
||||
@property
|
||||
def read_timeout(self) -> Optional[float]:
|
||||
"""See :attr:`BaseRequest.read_timeout`.
|
||||
|
||||
Returns:
|
||||
:obj:`float` | :obj:`None`: The default read timeout in seconds as passed to
|
||||
:paramref:`HTTPXRequest.read_timeout`.
|
||||
"""
|
||||
return self._client.timeout.read
|
||||
|
||||
def _build_client(self) -> httpx.AsyncClient:
|
||||
return httpx.AsyncClient(**self._client_kwargs) # type: ignore[arg-type]
|
||||
|
||||
@@ -188,17 +238,25 @@ class HTTPXRequest(BaseRequest):
|
||||
if self._client.is_closed:
|
||||
raise RuntimeError("This HTTPXRequest is not initialized!")
|
||||
|
||||
files = request_data.multipart_data if request_data else None
|
||||
data = request_data.json_parameters if request_data else None
|
||||
|
||||
# If user did not specify timeouts (for e.g. in a bot method), use the default ones when we
|
||||
# created this instance.
|
||||
if isinstance(read_timeout, DefaultValue):
|
||||
read_timeout = self._client.timeout.read
|
||||
if isinstance(write_timeout, DefaultValue):
|
||||
write_timeout = self._client.timeout.write
|
||||
if isinstance(connect_timeout, DefaultValue):
|
||||
connect_timeout = self._client.timeout.connect
|
||||
if isinstance(pool_timeout, DefaultValue):
|
||||
pool_timeout = self._client.timeout.pool
|
||||
|
||||
if isinstance(write_timeout, DefaultValue):
|
||||
# Making the networking backend decide on the proper timeout values instead of doing
|
||||
# it via the default values of the Bot methods was introduced in version 20.7.
|
||||
# We hard-code the value here for now until we add additional parameters to this
|
||||
# class to control the media_write_timeout separately.
|
||||
write_timeout = self._client.timeout.write if not files else 20
|
||||
|
||||
timeout = httpx.Timeout(
|
||||
connect=connect_timeout,
|
||||
read=read_timeout,
|
||||
@@ -206,15 +264,6 @@ class HTTPXRequest(BaseRequest):
|
||||
pool=pool_timeout,
|
||||
)
|
||||
|
||||
# TODO p0: On Linux, use setsockopt to properly set socket level keepalive.
|
||||
# (socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 120)
|
||||
# (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 30)
|
||||
# (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 8)
|
||||
# TODO p4: Support setsockopt on lesser platforms than Linux.
|
||||
|
||||
files = request_data.multipart_data if request_data else None
|
||||
data = request_data.json_parameters if request_data else None
|
||||
|
||||
try:
|
||||
res = await self._client.request(
|
||||
method=method,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
#! /usr/bin/env python
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ complete and correct. To run it, export an environment variable first:
|
||||
|
||||
$ export TEST_OFFICIAL=true
|
||||
|
||||
and then run ``pytest tests/test_official.py``.
|
||||
and then run ``pytest tests/test_official.py``. Note: You need py 3.10+ to run this test.
|
||||
|
||||
We also have another marker, ``@pytest.mark.dev``, which you can add to tests that you want to run selectively.
|
||||
Use as follows:
|
||||
|
||||
@@ -322,7 +322,7 @@ class TestAnimationWithRequest(TestAnimationBase):
|
||||
)
|
||||
assert message.reply_to_message is None
|
||||
else:
|
||||
with pytest.raises(BadRequest, match="message not found"):
|
||||
with pytest.raises(BadRequest, match="Message to reply not found"):
|
||||
await default_bot.send_animation(
|
||||
chat_id, animation, reply_to_message_id=reply_to_message.message_id
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user