mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-21 16:45:17 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 90729c21d7 | |||
| 55e3ecf9f8 | |||
| 8d2c7af1f3 | |||
| e86ae25a62 | |||
| 2d3357bfeb | |||
| b6f4783fd3 | |||
| f94ea9acbb | |||
| 157652cfdf | |||
| 104d0127aa | |||
| e0b22e60b4 | |||
| 16613d7ce0 | |||
| eac7f02211 | |||
| 28ded6718e | |||
| 13a641b3d7 | |||
| 27cccc7734 | |||
| f7ec7a7c4c | |||
| 8d6970ab02 | |||
| 1dc67dcbda | |||
| 14f712b3c4 | |||
| 0fb0fbb93f |
@@ -117,7 +117,7 @@ Here's how to make a one-off code change.
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ export TEST_OFFICIAL=True
|
||||
$ export TEST_OFFICIAL=true
|
||||
|
||||
prior to running the tests.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: Question
|
||||
about: Get help with errors or general questions
|
||||
title: "[QUESTION]"
|
||||
labels: 'question :question:'
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 5
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 2
|
||||
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
||||
onlyLabels: question
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: false
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: >
|
||||
This issue has been automatically closed due to inactivity. Feel free to comment in order to reopen
|
||||
or ask again in our Telegram support group at https://t.me/pythontelegrambotgroup.
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.5, 3.6, 3.7]
|
||||
python-version: [3.5, 3.6, 3.7, 3.8]
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
exit ${global_exit}
|
||||
env:
|
||||
JOB_INDEX: ${{ strategy.job-index }}
|
||||
BOTS: W3sidG9rZW4iOiAiNjk2MTg4NzMyOkFBR1Z3RUtmSEhsTmpzY3hFRE5LQXdraEdzdFpfa28xbUMwIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WldGaU1UUmxNbVF5TnpNeSIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIENQeXRob24gMi43IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19jcHl0aG9uXzI3X2JvdCJ9LCB7InRva2VuIjogIjY3MTQ2ODg4NjpBQUdQR2ZjaVJJQlVORmU4MjR1SVZkcTdKZTNfWW5BVE5HdyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpHWXdPVGxrTXpNeE4yWTIiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIFRyYXZpcyB1c2luZyBDUHl0aG9uIDMuNCIsICJib3RfdXNlcm5hbWUiOiAiQHB0Yl90cmF2aXNfY3B5dGhvbl8zNF9ib3QifSwgeyJ0b2tlbiI6ICI2MjkzMjY1Mzg6QUFGUnJaSnJCN29CM211ekdzR0pYVXZHRTVDUXpNNUNVNG8iLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpNbU01WVdKaFl6a3hNMlUxIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBvbiBUcmF2aXMgdXNpbmcgQ1B5dGhvbiAzLjUiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfdHJhdmlzX2NweXRob25fMzVfYm90In0sIHsidG9rZW4iOiAiNjQwMjA4OTQzOkFBRmhCalFwOXFtM1JUeFN6VXBZekJRakNsZS1Kano1aGNrIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WXpoa1pUZzFOamMxWXpWbCIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIENQeXRob24gMy42IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19jcHl0aG9uXzM2X2JvdCJ9LCB7InRva2VuIjogIjY5NTEwNDA4ODpBQUhmenlsSU9qU0lJUy1lT25JMjB5MkUyMEhvZEhzZnotMCIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOk9HUTFNRGd3WmpJd1pqRmwiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIFRyYXZpcyB1c2luZyBDUHl0aG9uIDMuNyIsICJib3RfdXNlcm5hbWUiOiAiQHB0Yl90cmF2aXNfY3B5dGhvbl8zN19ib3QifSwgeyJ0b2tlbiI6ICI2OTE0MjM1NTQ6QUFGOFdrakNaYm5IcVBfaTZHaFRZaXJGRWxackdhWU9oWDAiLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpZamM1TlRoaU1tUXlNV1ZoIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBvbiBUcmF2aXMgdXNpbmcgUHlQeSAyLjciLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfdHJhdmlzX3B5cHlfMjdfYm90In0sIHsidG9rZW4iOiAiNjg0MzM5OTg0OkFBRk1nRUVqcDAxcjVyQjAwN3lDZFZOc2c4QWxOc2FVLWNjIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TVRBek1UWTNNR1V5TmpnMCIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIFB5UHkgMy41IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19weXB5XzM1X2JvdCJ9LCB7InRva2VuIjogIjY5MDA5MTM0NzpBQUZMbVI1cEFCNVljcGVfbU9oN3pNNEpGQk9oMHozVDBUbyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpEaGxOekU1TURrd1lXSmkiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIEFwcFZleW9yIHVzaW5nIENQeXRob24gMy40IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX2FwcHZleW9yX2NweXRob25fMzRfYm90In0sIHsidG9rZW4iOiAiNjk0MzA4MDUyOkFBRUIyX3NvbkNrNTVMWTlCRzlBTy1IOGp4aVBTNTVvb0JBIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WW1aaVlXWm1NakpoWkdNeSIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gQXBwVmV5b3IgdXNpbmcgQ1B5dGhvbiAyLjciLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfYXBwdmV5b3JfY3B5dGhvbl8yN19ib3QifV0=
|
||||
BOTS: W3sidG9rZW4iOiAiNjk2MTg4NzMyOkFBR1Z3RUtmSEhsTmpzY3hFRE5LQXdraEdzdFpfa28xbUMwIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WldGaU1UUmxNbVF5TnpNeSIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIENQeXRob24gMi43IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19jcHl0aG9uXzI3X2JvdCJ9LCB7InRva2VuIjogIjY3MTQ2ODg4NjpBQUdQR2ZjaVJJQlVORmU4MjR1SVZkcTdKZTNfWW5BVE5HdyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpHWXdPVGxrTXpNeE4yWTIiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIFRyYXZpcyB1c2luZyBDUHl0aG9uIDMuNCIsICJib3RfdXNlcm5hbWUiOiAiQHB0Yl90cmF2aXNfY3B5dGhvbl8zNF9ib3QifSwgeyJ0b2tlbiI6ICI2MjkzMjY1Mzg6QUFGUnJaSnJCN29CM211ekdzR0pYVXZHRTVDUXpNNUNVNG8iLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpNbU01WVdKaFl6a3hNMlUxIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBvbiBUcmF2aXMgdXNpbmcgQ1B5dGhvbiAzLjUiLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfdHJhdmlzX2NweXRob25fMzVfYm90In0sIHsidG9rZW4iOiAiNjQwMjA4OTQzOkFBRmhCalFwOXFtM1JUeFN6VXBZekJRakNsZS1Kano1aGNrIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WXpoa1pUZzFOamMxWXpWbCIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIENQeXRob24gMy42IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19jcHl0aG9uXzM2X2JvdCJ9LCB7InRva2VuIjogIjY5NTEwNDA4ODpBQUhmenlsSU9qU0lJUy1lT25JMjB5MkUyMEhvZEhzZnotMCIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOk9HUTFNRGd3WmpJd1pqRmwiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIFRyYXZpcyB1c2luZyBDUHl0aG9uIDMuNyIsICJib3RfdXNlcm5hbWUiOiAiQHB0Yl90cmF2aXNfY3B5dGhvbl8zN19ib3QifSwgeyJ0b2tlbiI6ICI2OTE0MjM1NTQ6QUFGOFdrakNaYm5IcVBfaTZHaFRZaXJGRWxackdhWU9oWDAiLCAicGF5bWVudF9wcm92aWRlcl90b2tlbiI6ICIyODQ2ODUwNjM6VEVTVDpZamM1TlRoaU1tUXlNV1ZoIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBvbiBUcmF2aXMgdXNpbmcgUHlQeSAyLjciLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfdHJhdmlzX3B5cHlfMjdfYm90In0sIHsidG9rZW4iOiAiNjg0MzM5OTg0OkFBRk1nRUVqcDAxcjVyQjAwN3lDZFZOc2c4QWxOc2FVLWNjIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TVRBek1UWTNNR1V5TmpnMCIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gVHJhdmlzIHVzaW5nIFB5UHkgMy41IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX3RyYXZpc19weXB5XzM1X2JvdCJ9LCB7InRva2VuIjogIjY5MDA5MTM0NzpBQUZMbVI1cEFCNVljcGVfbU9oN3pNNEpGQk9oMHozVDBUbyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOlpEaGxOekU1TURrd1lXSmkiLCAiYm90X25hbWUiOiAiUFRCIHRlc3RzIG9uIEFwcFZleW9yIHVzaW5nIENQeXRob24gMy40IiwgImJvdF91c2VybmFtZSI6ICJAcHRiX2FwcHZleW9yX2NweXRob25fMzRfYm90In0sIHsidG9rZW4iOiAiNjk0MzA4MDUyOkFBRUIyX3NvbkNrNTVMWTlCRzlBTy1IOGp4aVBTNTVvb0JBIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WW1aaVlXWm1NakpoWkdNeSIsICJib3RfbmFtZSI6ICJQVEIgdGVzdHMgb24gQXBwVmV5b3IgdXNpbmcgQ1B5dGhvbiAyLjciLCAiYm90X3VzZXJuYW1lIjogIkBwdGJfYXBwdmV5b3JfY3B5dGhvbl8yN19ib3QifSwgeyJ0b2tlbiI6ICIxMDU1Mzk3NDcxOkFBRzE4bkJfUzJXQXd1SjNnN29oS0JWZ1hYY2VNbklPeVNjIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TmpBd056QXpZalZpTkdOayIsICJuYW1lIjogIlBUQiB0ZXN0cyBbMF0iLCAidXNlcm5hbWUiOiAicHRiXzBfYm90In0sIHsidG9rZW4iOiAiMTA0NzMyNjc3MTpBQUY4bk90ODFGcFg4bGJidno4VWV3UVF2UmZUYkZmQnZ1SSIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOllUVTFOVEk0WkdSallqbGkiLCAibmFtZSI6ICJQVEIgdGVzdHMgWzFdIiwgInVzZXJuYW1lIjogInB0Yl8xX2JvdCJ9LCB7InRva2VuIjogIjk3MTk5Mjc0NTpBQUdPa09hVzBOSGpnSXY1LTlqUWJPajR2R3FkaFNGLVV1cyIsICJwYXltZW50X3Byb3ZpZGVyX3Rva2VuIjogIjI4NDY4NTA2MzpURVNUOk5XWmtNV1ZoWWpsallqVTUiLCAibmFtZSI6ICJQVEIgdGVzdHMgWzJdIiwgInVzZXJuYW1lIjogInB0Yl8yX2JvdCJ9XQ==
|
||||
TEST_BUILD: ${{ matrix.test-build }}
|
||||
TEST_PRE_COMMIT: ${{ matrix.test-pre-commit }}
|
||||
shell: bash --noprofile --norc {0}
|
||||
@@ -90,7 +90,6 @@ jobs:
|
||||
run: |
|
||||
pytest -v tests/test_official.py
|
||||
exit $?
|
||||
continue-on-error: True
|
||||
env:
|
||||
TEST_OFFICIAL: "true"
|
||||
shell: bash --noprofile --norc {0}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
repos:
|
||||
- repo: git://github.com/python-telegram-bot/mirrors-yapf
|
||||
sha: 5769e088ef6e0a0d1eb63bd6d0c1fe9f3606d6c8
|
||||
rev: 5769e088ef6e0a0d1eb63bd6d0c1fe9f3606d6c8
|
||||
hooks:
|
||||
- id: yapf
|
||||
files: ^(telegram|tests)/.*\.py$
|
||||
args:
|
||||
- --diff
|
||||
- repo: git://github.com/pre-commit/pre-commit-hooks
|
||||
sha: 0b70e285e369bcb24b57b74929490ea7be9c4b19
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.7.1
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: git://github.com/pre-commit/mirrors-pylint
|
||||
sha: 9d8dcbc2b86c796275680f239c1e90dcd50bd398
|
||||
rev: 9d8dcbc2b86c796275680f239c1e90dcd50bd398
|
||||
hooks:
|
||||
- id: pylint
|
||||
files: ^telegram/.*\.py$
|
||||
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
language: python
|
||||
matrix:
|
||||
include:
|
||||
- python: 2.7
|
||||
- python: 3.5
|
||||
- python: 3.6
|
||||
- python: 3.7
|
||||
dist: xenial
|
||||
sudo: true
|
||||
- python: 3.7
|
||||
dist: xenial
|
||||
env: TEST_OFFICIAL=true
|
||||
- python: pypy2.7-5.10.0
|
||||
dist: xenial
|
||||
- python: pypy3.5-5.10.1
|
||||
dist: xenial
|
||||
- python: 3.8-dev
|
||||
dist: xenial
|
||||
allow_failures:
|
||||
- python: pypy2.7-5.10.0
|
||||
- python: pypy3.5-5.10.1
|
||||
|
||||
dist: trusty
|
||||
sudo: false
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^[vV]\d+$/
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cache/pip
|
||||
- $HOME/.pre-commit
|
||||
before_cache:
|
||||
- rm -f $HOME/.cache/pip/log/debug.log
|
||||
- rm -f $HOME/.pre-commit/pre-commit.log
|
||||
|
||||
install:
|
||||
# fix TypeError from old version of this
|
||||
- pip install -U codecov pytest-cov
|
||||
- echo $TRAVIS_PYTHON_VERSION
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == '3.7'* ]]; then pip install -U git+https://github.com/yaml/pyyaml.git; else true; fi
|
||||
- pip install -U -r requirements.txt
|
||||
- pip install -U -r requirements-dev.txt
|
||||
- if [[ $TRAVIS_PYTHON_VERSION != 'pypy'* ]]; then pip install ujson; else true; fi
|
||||
|
||||
script:
|
||||
- if [[ $TEST_OFFICIAL != 'true' ]]; then pytest -v -m nocoverage; else true; fi
|
||||
- if [[ $TEST_OFFICIAL != 'true' ]]; then pytest -v -m "not nocoverage" --cov; else true; fi
|
||||
- if [[ $TEST_OFFICIAL == 'true' ]]; then pytest -v tests/test_official.py; else true; fi
|
||||
|
||||
after_success:
|
||||
- coverage combine
|
||||
- codecov -F Travis
|
||||
@@ -36,6 +36,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `Evan Haberecht <https://github.com/habereet>`_
|
||||
- `evgfilim1 <https://github.com/evgfilim1>`_
|
||||
- `franciscod <https://github.com/franciscod>`_
|
||||
- `gamgi <https://github.com/gamgi>`_
|
||||
- `Hugo Damer <https://github.com/HakimusGIT>`_
|
||||
- `ihoru <https://github.com/ihoru>`_
|
||||
- `Jasmin Bom <https://github.com/jsmnbom>`_
|
||||
|
||||
+45
@@ -2,6 +2,51 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
Version 12.5
|
||||
============
|
||||
*Released 2020-03-29*
|
||||
|
||||
**New Features:**
|
||||
|
||||
- `Bot.link` gives the `t.me` link of the bot (`#1770`_)
|
||||
|
||||
**Major Changes:**
|
||||
|
||||
- Bot API 4.5 and 4.6 support. (`#1508`_, `#1723`_)
|
||||
|
||||
**Minor changes, CI improvements or bug fixes:**
|
||||
|
||||
- Remove legacy CI files (`#1783`_, `#1791`_)
|
||||
- Update pre-commit config file (`#1787`_)
|
||||
- Remove builtin names (`#1792`_)
|
||||
- CI improvements (`#1808`_, `#1848`_)
|
||||
- Support Python 3.8 (`#1614`_, `#1824`_)
|
||||
- Use stale bot for auto closing stale issues (`#1820`_, `#1829`_, `#1840`_)
|
||||
- Doc fixes (`#1778`_, `#1818`_)
|
||||
- Fix typo in `edit_message_media` (`#1779`_)
|
||||
- In examples, answer CallbackQueries and use `edit_message_text` shortcut (`#1721`_)
|
||||
- Revert accidental change in vendored urllib3 (`#1775`_)
|
||||
|
||||
.. _`#1783`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1783
|
||||
.. _`#1787`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1787
|
||||
.. _`#1792`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1792
|
||||
.. _`#1791`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1791
|
||||
.. _`#1808`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1808
|
||||
.. _`#1614`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1614
|
||||
.. _`#1770`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1770
|
||||
.. _`#1824`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1824
|
||||
.. _`#1820`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1820
|
||||
.. _`#1829`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1829
|
||||
.. _`#1840`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1840
|
||||
.. _`#1778`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1778
|
||||
.. _`#1779`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1779
|
||||
.. _`#1721`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1721
|
||||
.. _`#1775`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1775
|
||||
.. _`#1848`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1848
|
||||
.. _`#1818`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1818
|
||||
.. _`#1508`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1508
|
||||
.. _`#1723`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1723
|
||||
|
||||
Version 12.4.2
|
||||
==============
|
||||
*Released 2020-02-10*
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ make the development of bots easy and straightforward. These classes are contain
|
||||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **4.1** are supported.
|
||||
All types and methods of the Telegram Bot API **4.6** are supported.
|
||||
|
||||
==========
|
||||
Installing
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
environment:
|
||||
|
||||
matrix:
|
||||
# For Python versions available on Appveyor, see
|
||||
# https://www.appveyor.com/docs/windows-images-software/#python
|
||||
# The list here is complete (excluding Python 2.6, which
|
||||
# isn't covered by this document) at the time of writing.
|
||||
|
||||
- PYTHON: "C:\\Python27"
|
||||
- PYTHON: "C:\\Python35"
|
||||
- PYTHON: "C:\\Python36"
|
||||
- PYTHON: "C:\\Python37"
|
||||
# - PYTHON: "C:\\Python38"
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^[vV]\d+$/
|
||||
|
||||
skip_branch_with_pr: true
|
||||
|
||||
max_jobs: 1
|
||||
|
||||
install:
|
||||
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
||||
- "git submodule update --init --recursive"
|
||||
# Check that we have the expected version and architecture for Python
|
||||
- "python --version"
|
||||
# We need wheel installed to build wheels
|
||||
# fix TypeError from an old version of this
|
||||
- "pip install attrs==17.4.0"
|
||||
- "pip install -U codecov pytest-cov"
|
||||
- "pip install -r requirements.txt"
|
||||
- "pip install -r requirements-dev.txt"
|
||||
|
||||
build: off
|
||||
|
||||
test_script:
|
||||
- "pytest --version"
|
||||
- "pytest -m \"not nocoverage\" --cov --cov-report xml:coverage.xml"
|
||||
|
||||
after_test:
|
||||
- "codecov -f coverage.xml -F Appveyor"
|
||||
+2
-2
@@ -58,9 +58,9 @@ author = u'Leandro Toledo'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '12.4' # telegram.__version__[:3]
|
||||
version = '12.5' # telegram.__version__[:3]
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '12.4.2' # telegram.__version__
|
||||
release = '12.5' # telegram.__version__
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
telegram.KeyboardButtonPollType
|
||||
===============================
|
||||
|
||||
.. autoclass:: telegram.KeyboardButtonPollType
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
telegram.PollAnswer
|
||||
===================
|
||||
|
||||
.. autoclass:: telegram.PollAnswer
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -31,6 +31,7 @@ telegram package
|
||||
telegram.inputmediaphoto
|
||||
telegram.inputmediavideo
|
||||
telegram.keyboardbutton
|
||||
telegram.keyboardbuttonpolltype
|
||||
telegram.location
|
||||
telegram.loginurl
|
||||
telegram.message
|
||||
@@ -38,6 +39,7 @@ telegram package
|
||||
telegram.parsemode
|
||||
telegram.photosize
|
||||
telegram.poll
|
||||
telegram.pollanswer
|
||||
telegram.polloption
|
||||
telegram.replykeyboardremove
|
||||
telegram.replykeyboardmarkup
|
||||
|
||||
@@ -29,6 +29,10 @@ def start(update, context):
|
||||
def button(update, context):
|
||||
query = update.callback_query
|
||||
|
||||
# CallbackQueries need to be answered, even if no notification to the user is needed
|
||||
# Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery
|
||||
query.answer()
|
||||
|
||||
query.edit_message_text(text="Selected option: {}".format(query.data))
|
||||
|
||||
|
||||
|
||||
+14
-25
@@ -55,8 +55,9 @@ def start_over(update, context):
|
||||
"""Prompt same text & keyboard as `start` does but not as new message"""
|
||||
# Get CallbackQuery from Update
|
||||
query = update.callback_query
|
||||
# Get Bot from CallbackContext
|
||||
bot = context.bot
|
||||
# CallbackQueries need to be answered, even if no notification to the user is needed
|
||||
# Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery
|
||||
query.answer()
|
||||
keyboard = [
|
||||
[InlineKeyboardButton("1", callback_data=str(ONE)),
|
||||
InlineKeyboardButton("2", callback_data=str(TWO))]
|
||||
@@ -65,9 +66,7 @@ def start_over(update, context):
|
||||
# Instead of sending a new message, edit the message that
|
||||
# originated the CallbackQuery. This gives the feeling of an
|
||||
# interactive menu.
|
||||
bot.edit_message_text(
|
||||
chat_id=query.message.chat_id,
|
||||
message_id=query.message.message_id,
|
||||
query.edit_message_text(
|
||||
text="Start handler, Choose a route",
|
||||
reply_markup=reply_markup
|
||||
)
|
||||
@@ -77,15 +76,13 @@ def start_over(update, context):
|
||||
def one(update, context):
|
||||
"""Show new choice of buttons"""
|
||||
query = update.callback_query
|
||||
bot = context.bot
|
||||
query.answer()
|
||||
keyboard = [
|
||||
[InlineKeyboardButton("3", callback_data=str(THREE)),
|
||||
InlineKeyboardButton("4", callback_data=str(FOUR))]
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
bot.edit_message_text(
|
||||
chat_id=query.message.chat_id,
|
||||
message_id=query.message.message_id,
|
||||
query.edit_message_text(
|
||||
text="First CallbackQueryHandler, Choose a route",
|
||||
reply_markup=reply_markup
|
||||
)
|
||||
@@ -95,15 +92,13 @@ def one(update, context):
|
||||
def two(update, context):
|
||||
"""Show new choice of buttons"""
|
||||
query = update.callback_query
|
||||
bot = context.bot
|
||||
query.answer()
|
||||
keyboard = [
|
||||
[InlineKeyboardButton("1", callback_data=str(ONE)),
|
||||
InlineKeyboardButton("3", callback_data=str(THREE))]
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
bot.edit_message_text(
|
||||
chat_id=query.message.chat_id,
|
||||
message_id=query.message.message_id,
|
||||
query.edit_message_text(
|
||||
text="Second CallbackQueryHandler, Choose a route",
|
||||
reply_markup=reply_markup
|
||||
)
|
||||
@@ -113,15 +108,13 @@ def two(update, context):
|
||||
def three(update, context):
|
||||
"""Show new choice of buttons"""
|
||||
query = update.callback_query
|
||||
bot = context.bot
|
||||
query.answer()
|
||||
keyboard = [
|
||||
[InlineKeyboardButton("Yes, let's do it again!", callback_data=str(ONE)),
|
||||
InlineKeyboardButton("Nah, I've had enough ...", callback_data=str(TWO))]
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
bot.edit_message_text(
|
||||
chat_id=query.message.chat_id,
|
||||
message_id=query.message.message_id,
|
||||
query.edit_message_text(
|
||||
text="Third CallbackQueryHandler. Do want to start over?",
|
||||
reply_markup=reply_markup
|
||||
)
|
||||
@@ -132,15 +125,13 @@ def three(update, context):
|
||||
def four(update, context):
|
||||
"""Show new choice of buttons"""
|
||||
query = update.callback_query
|
||||
bot = context.bot
|
||||
query.answer()
|
||||
keyboard = [
|
||||
[InlineKeyboardButton("2", callback_data=str(TWO)),
|
||||
InlineKeyboardButton("4", callback_data=str(FOUR))]
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
bot.edit_message_text(
|
||||
chat_id=query.message.chat_id,
|
||||
message_id=query.message.message_id,
|
||||
query.edit_message_text(
|
||||
text="Fourth CallbackQueryHandler, Choose a route",
|
||||
reply_markup=reply_markup
|
||||
)
|
||||
@@ -151,10 +142,8 @@ def end(update, context):
|
||||
"""Returns `ConversationHandler.END`, which tells the
|
||||
ConversationHandler that the conversation is over"""
|
||||
query = update.callback_query
|
||||
bot = context.bot
|
||||
bot.edit_message_text(
|
||||
chat_id=query.message.chat_id,
|
||||
message_id=query.message.message_id,
|
||||
query.answer()
|
||||
query.edit_message_text(
|
||||
text="See you next time!"
|
||||
)
|
||||
return ConversationHandler.END
|
||||
|
||||
@@ -66,6 +66,7 @@ def start(update, context):
|
||||
|
||||
# If we're starting over we don't need do send a new message
|
||||
if context.user_data.get(START_OVER):
|
||||
update.callback_query.answer()
|
||||
update.callback_query.edit_message_text(text=text, reply_markup=keyboard)
|
||||
else:
|
||||
update.message.reply_text('Hi, I\'m FamiliyBot and here to help you gather information'
|
||||
@@ -83,6 +84,7 @@ def adding_self(update, context):
|
||||
button = InlineKeyboardButton(text='Add info', callback_data=str(MALE))
|
||||
keyboard = InlineKeyboardMarkup.from_button(button)
|
||||
|
||||
update.callback_query.answer()
|
||||
update.callback_query.edit_message_text(text=text, reply_markup=keyboard)
|
||||
|
||||
return DESCRIBING_SELF
|
||||
@@ -118,6 +120,7 @@ def show_data(update, context):
|
||||
]]
|
||||
keyboard = InlineKeyboardMarkup(buttons)
|
||||
|
||||
update.callback_query.answer()
|
||||
update.callback_query.edit_message_text(text=text, reply_markup=keyboard)
|
||||
ud[START_OVER] = True
|
||||
|
||||
@@ -133,6 +136,8 @@ def stop(update, context):
|
||||
|
||||
def end(update, context):
|
||||
"""End conversation from InlineKeyboardButton."""
|
||||
update.callback_query.answer()
|
||||
|
||||
text = 'See you around!'
|
||||
update.callback_query.edit_message_text(text=text)
|
||||
|
||||
@@ -151,6 +156,8 @@ def select_level(update, context):
|
||||
InlineKeyboardButton(text='Back', callback_data=str(END))
|
||||
]]
|
||||
keyboard = InlineKeyboardMarkup(buttons)
|
||||
|
||||
update.callback_query.answer()
|
||||
update.callback_query.edit_message_text(text=text, reply_markup=keyboard)
|
||||
|
||||
return SELECTING_LEVEL
|
||||
@@ -172,8 +179,9 @@ def select_gender(update, context):
|
||||
InlineKeyboardButton(text='Show data', callback_data=str(SHOWING)),
|
||||
InlineKeyboardButton(text='Back', callback_data=str(END))
|
||||
]]
|
||||
|
||||
keyboard = InlineKeyboardMarkup(buttons)
|
||||
|
||||
update.callback_query.answer()
|
||||
update.callback_query.edit_message_text(text=text, reply_markup=keyboard)
|
||||
|
||||
return SELECTING_GENDER
|
||||
@@ -201,6 +209,8 @@ def select_feature(update, context):
|
||||
if not context.user_data.get(START_OVER):
|
||||
context.user_data[FEATURES] = {GENDER: update.callback_query.data}
|
||||
text = 'Please select a feature to update.'
|
||||
|
||||
update.callback_query.answer()
|
||||
update.callback_query.edit_message_text(text=text, reply_markup=keyboard)
|
||||
# But after we do that, we need to send a new message
|
||||
else:
|
||||
@@ -215,6 +225,8 @@ def ask_for_input(update, context):
|
||||
"""Prompt user to input data for selected feature."""
|
||||
context.user_data[CURRENT_FEATURE] = update.callback_query.data
|
||||
text = 'Okay, tell me.'
|
||||
|
||||
update.callback_query.answer()
|
||||
update.callback_query.edit_message_text(text=text)
|
||||
|
||||
return TYPING
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
Basic example for a bot that works with polls. Only 3 people are allowed to interact with each
|
||||
poll/quiz the bot generates. The preview command generates a closed poll/quiz, excatly like the
|
||||
one the user sends the bot
|
||||
"""
|
||||
import logging
|
||||
|
||||
from telegram import (Poll, ParseMode, KeyboardButton, KeyboardButtonPollType,
|
||||
ReplyKeyboardMarkup, ReplyKeyboardRemove)
|
||||
from telegram.ext import (Updater, CommandHandler, PollAnswerHandler, PollHandler, MessageHandler,
|
||||
Filters)
|
||||
from telegram.utils.helpers import mention_html
|
||||
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def start(update, context):
|
||||
"""Inform user about what this bot can do"""
|
||||
update.message.reply_text('Please select /poll to get a Poll, /quiz to get a Quiz or /preview'
|
||||
' to generate a preview for your poll')
|
||||
|
||||
|
||||
def poll(update, context):
|
||||
"""Sends a predefined poll"""
|
||||
questions = ["Good", "Really good", "Fantastic", "Great"]
|
||||
message = context.bot.send_poll(update.effective_user.id, "How are you?", questions,
|
||||
is_anonymous=False, allows_multiple_answers=True)
|
||||
# Save some info about the poll the bot_data for later use in receive_poll_answer
|
||||
payload = {message.poll.id: {"questions": questions, "message_id": message.message_id,
|
||||
"chat_id": update.effective_chat.id, "answers": 0}}
|
||||
context.bot_data.update(payload)
|
||||
|
||||
|
||||
def receive_poll_answer(update, context):
|
||||
"""Summarize a users poll vote"""
|
||||
answer = update.poll_answer
|
||||
poll_id = answer.poll_id
|
||||
try:
|
||||
questions = context.bot_data[poll_id]["questions"]
|
||||
# this means this poll answer update is from an old poll, we can't do our answering then
|
||||
except KeyError:
|
||||
return
|
||||
selected_options = answer.option_ids
|
||||
answer_string = ""
|
||||
for question_id in selected_options:
|
||||
if question_id != selected_options[-1]:
|
||||
answer_string += questions[question_id] + " and "
|
||||
else:
|
||||
answer_string += questions[question_id]
|
||||
user_mention = mention_html(update.effective_user.id, update.effective_user.full_name)
|
||||
context.bot.send_message(context.bot_data[poll_id]["chat_id"],
|
||||
"{} feels {}!".format(user_mention, answer_string),
|
||||
parse_mode=ParseMode.HTML)
|
||||
context.bot_data[poll_id]["answers"] += 1
|
||||
# Close poll after three participants voted
|
||||
if context.bot_data[poll_id]["answers"] == 3:
|
||||
context.bot.stop_poll(context.bot_data[poll_id]["chat_id"],
|
||||
context.bot_data[poll_id]["message_id"])
|
||||
|
||||
|
||||
def quiz(update, context):
|
||||
"""Send a predefined poll"""
|
||||
questions = ["1", "2", "4", "20"]
|
||||
message = update.effective_message.reply_poll("How many eggs do you need for a cake?",
|
||||
questions, type=Poll.QUIZ, correct_option_id=2)
|
||||
# Save some info about the poll the bot_data for later use in receive_quiz_answer
|
||||
payload = {message.poll.id: {"chat_id": update.effective_chat.id,
|
||||
"message_id": message.message_id}}
|
||||
context.bot_data.update(payload)
|
||||
|
||||
|
||||
def receive_quiz_answer(update, context):
|
||||
"""Close quiz after three participants took it"""
|
||||
# the bot can receive closed poll updates we don't care about
|
||||
if update.poll.is_closed:
|
||||
return
|
||||
if update.poll.total_voter_count == 3:
|
||||
try:
|
||||
quiz_data = context.bot_data[update.poll.id]
|
||||
# this means this poll answer update is from an old poll, we can't stop it then
|
||||
except KeyError:
|
||||
return
|
||||
context.bot.stop_poll(quiz_data["chat_id"], quiz_data["message_id"])
|
||||
|
||||
|
||||
def preview(update, context):
|
||||
"""Ask user to create a poll and display a preview of it"""
|
||||
# using this without a type lets the user chooses what he wants (quiz or poll)
|
||||
button = [[KeyboardButton("Press me!", request_poll=KeyboardButtonPollType())]]
|
||||
message = "Press the button to let the bot generate a preview for your poll"
|
||||
# using one_time_keyboard to hide the keyboard
|
||||
update.effective_message.reply_text(message,
|
||||
reply_markup=ReplyKeyboardMarkup(button,
|
||||
one_time_keyboard=True))
|
||||
|
||||
|
||||
def receive_poll(update, context):
|
||||
"""On receiving polls, reply to it by a closed poll copying the received poll"""
|
||||
actual_poll = update.effective_message.poll
|
||||
# Only need to set the question and options, since all other parameters don't matter for
|
||||
# a closed poll
|
||||
update.effective_message.reply_poll(
|
||||
question=actual_poll.question,
|
||||
options=[o.text for o in actual_poll.options],
|
||||
# with is_closed true, the poll/quiz is immediately closed
|
||||
is_closed=True,
|
||||
reply_markup=ReplyKeyboardRemove()
|
||||
)
|
||||
|
||||
|
||||
def help_handler(update, context):
|
||||
"""Display a help message"""
|
||||
update.message.reply_text("Use /quiz, /poll or /preview to test this "
|
||||
"bot.")
|
||||
|
||||
|
||||
def main():
|
||||
# Create the Updater and pass it your bot's token.
|
||||
# Make sure to set use_context=True to use the new context based callbacks
|
||||
# Post version 12 this will no longer be necessary
|
||||
updater = Updater("TOKEN", use_context=True)
|
||||
dp = updater.dispatcher
|
||||
dp.add_handler(CommandHandler('start', start))
|
||||
dp.add_handler(CommandHandler('poll', poll))
|
||||
dp.add_handler(PollAnswerHandler(receive_poll_answer))
|
||||
dp.add_handler(CommandHandler('quiz', quiz))
|
||||
dp.add_handler(PollHandler(receive_quiz_answer))
|
||||
dp.add_handler(CommandHandler('preview', preview))
|
||||
dp.add_handler(MessageHandler(Filters.poll, receive_poll))
|
||||
dp.add_handler(CommandHandler('help', help_handler))
|
||||
|
||||
# Start the Bot
|
||||
updater.start_polling()
|
||||
|
||||
# Run the bot until the user presses Ctrl-C or the process receives SIGINT,
|
||||
# SIGTERM or SIGABRT
|
||||
updater.idle()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -63,5 +63,6 @@ with codecs.open('README.rst', 'r', 'utf-8') as fd:
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7'
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
],)
|
||||
|
||||
@@ -38,6 +38,7 @@ from .files.videonote import VideoNote
|
||||
from .chataction import ChatAction
|
||||
from .userprofilephotos import UserProfilePhotos
|
||||
from .keyboardbutton import KeyboardButton
|
||||
from .keyboardbuttonpolltype import KeyboardButtonPollType
|
||||
from .replymarkup import ReplyMarkup
|
||||
from .replykeyboardmarkup import ReplyKeyboardMarkup
|
||||
from .replykeyboardremove import ReplyKeyboardRemove
|
||||
@@ -48,7 +49,7 @@ from .files.file import File
|
||||
from .parsemode import ParseMode
|
||||
from .messageentity import MessageEntity
|
||||
from .games.game import Game
|
||||
from .poll import Poll, PollOption
|
||||
from .poll import Poll, PollOption, PollAnswer
|
||||
from .loginurl import LoginUrl
|
||||
from .games.callbackgame import CallbackGame
|
||||
from .payment.shippingaddress import ShippingAddress
|
||||
@@ -138,7 +139,7 @@ __all__ = [
|
||||
'InlineQueryResultPhoto', 'InlineQueryResultVenue', 'InlineQueryResultVideo',
|
||||
'InlineQueryResultVoice', 'InlineQueryResultGame', 'InputContactMessageContent', 'InputFile',
|
||||
'InputLocationMessageContent', 'InputMessageContent', 'InputTextMessageContent',
|
||||
'InputVenueMessageContent', 'KeyboardButton', 'Location', 'EncryptedCredentials',
|
||||
'InputVenueMessageContent', 'Location', 'EncryptedCredentials',
|
||||
'PassportFile', 'EncryptedPassportElement', 'PassportData', 'Message', 'MessageEntity',
|
||||
'ParseMode', 'PhotoSize', 'ReplyKeyboardRemove', 'ReplyKeyboardMarkup', 'ReplyMarkup',
|
||||
'Sticker', 'TelegramError', 'TelegramObject', 'Update', 'User', 'UserProfilePhotos', 'Venue',
|
||||
@@ -156,5 +157,5 @@ __all__ = [
|
||||
'InputMediaAudio', 'InputMediaDocument', 'TelegramDecryptionError',
|
||||
'PassportElementErrorSelfie', 'PassportElementErrorTranslationFile',
|
||||
'PassportElementErrorTranslationFiles', 'PassportElementErrorUnspecified', 'Poll',
|
||||
'PollOption', 'LoginUrl'
|
||||
'PollOption', 'PollAnswer', 'LoginUrl', 'KeyboardButton', 'KeyboardButtonPollType',
|
||||
]
|
||||
|
||||
+105
-9
@@ -223,6 +223,34 @@ class Bot(TelegramObject):
|
||||
|
||||
return self.bot.username
|
||||
|
||||
@property
|
||||
@info
|
||||
def link(self):
|
||||
""":obj:`str`: Convenience property. Returns the t.me link of the bot."""
|
||||
|
||||
return "https://t.me/{}".format(self.username)
|
||||
|
||||
@property
|
||||
@info
|
||||
def can_join_groups(self):
|
||||
""":obj:`str`: Bot's can_join_groups attribute."""
|
||||
|
||||
return self.bot.can_join_groups
|
||||
|
||||
@property
|
||||
@info
|
||||
def can_read_all_group_messages(self):
|
||||
""":obj:`str`: Bot's can_read_all_group_messages attribute."""
|
||||
|
||||
return self.bot.can_read_all_group_messages
|
||||
|
||||
@property
|
||||
@info
|
||||
def supports_inline_queries(self):
|
||||
""":obj:`str`: Bot's supports_inline_queries attribute."""
|
||||
|
||||
return self.bot.supports_inline_queries
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
""":obj:`str`: Bot's @username."""
|
||||
@@ -419,7 +447,7 @@ class Bot(TelegramObject):
|
||||
Internet, or upload a new photo using multipart/form-data. Lastly you can pass
|
||||
an existing :class:`telegram.PhotoSize` object to send.
|
||||
caption (:obj:`str`, optional): Photo caption (may also be used when resending photos
|
||||
by file_id), 0-1024 characters.
|
||||
by file_id), 0-1024 characters after entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to
|
||||
show bold, italic, fixed-width text or inline URLs in the media caption. See the
|
||||
constants in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -493,7 +521,8 @@ class Bot(TelegramObject):
|
||||
(recommended), pass an HTTP URL as a String for Telegram to get an audio file from
|
||||
the Internet, or upload a new one using multipart/form-data. Lastly you can pass
|
||||
an existing :class:`telegram.Audio` object to send.
|
||||
caption (:obj:`str`, optional): Audio caption, 0-1024 characters.
|
||||
caption (:obj:`str`, optional): Audio caption, 0-1024 characters after entities
|
||||
parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to
|
||||
show bold, italic, fixed-width text or inline URLs in the media caption. See the
|
||||
constants in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -579,7 +608,7 @@ class Bot(TelegramObject):
|
||||
filename (:obj:`str`, optional): File name that shows in telegram message (it is useful
|
||||
when you send file generated by temp module, for example). Undocumented.
|
||||
caption (:obj:`str`, optional): Document caption (may also be used when resending
|
||||
documents by file_id), 0-1024 characters.
|
||||
documents by file_id), 0-1024 characters after entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to
|
||||
show bold, italic, fixed-width text or inline URLs in the media caption. See the
|
||||
constants in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -715,7 +744,7 @@ class Bot(TelegramObject):
|
||||
width (:obj:`int`, optional): Video width.
|
||||
height (:obj:`int`, optional): Video height.
|
||||
caption (:obj:`str`, optional): Video caption (may also be used when resending videos
|
||||
by file_id), 0-1024 characters.
|
||||
by file_id), 0-1024 characters after entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to
|
||||
show bold, italic, fixed-width text or inline URLs in the media caption. See the
|
||||
constants in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -877,7 +906,7 @@ class Bot(TelegramObject):
|
||||
A thumbnail's width and height should not exceed 320. Ignored if the file is not
|
||||
is passed as a string or file_id.
|
||||
caption (:obj:`str`, optional): Animation caption (may also be used when resending
|
||||
animations by file_id), 0-1024 characters.
|
||||
animations by file_id), 0-1024 characters after entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to
|
||||
show bold, italic, fixed-width text or inline URLs in the media caption. See the
|
||||
constants in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -955,7 +984,8 @@ class Bot(TelegramObject):
|
||||
(recommended), pass an HTTP URL as a String for Telegram to get an voice file from
|
||||
the Internet, or upload a new one using multipart/form-data. Lastly you can pass
|
||||
an existing :class:`telegram.Voice` object to send.
|
||||
caption (:obj:`str`, optional): Voice message caption, 0-1024 characters.
|
||||
caption (:obj:`str`, optional): Voice message caption, 0-1024 characters after entities
|
||||
parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to
|
||||
show bold, italic, fixed-width text or inline URLs in the media caption. See the
|
||||
constants in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -1795,7 +1825,7 @@ class Bot(TelegramObject):
|
||||
Identifier of the sent message.
|
||||
inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not
|
||||
specified. Identifier of the inline message.
|
||||
text (:obj:`str`): New text of the message.
|
||||
text (:obj:`str`): New text of the message, 0-1024 characters after entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to
|
||||
show bold, italic, fixed-width text or inline URLs in your bot's message. See the
|
||||
constants in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -1932,7 +1962,7 @@ class Bot(TelegramObject):
|
||||
|
||||
if inline_message_id is None and (chat_id is None or message_id is None):
|
||||
raise ValueError(
|
||||
'edit_message_caption: Both chat_id and message_id are required when '
|
||||
'edit_message_media: Both chat_id and message_id are required when '
|
||||
'inline_message_id is not specified')
|
||||
|
||||
url = '{0}/editMessageMedia'.format(self.base_url)
|
||||
@@ -2932,6 +2962,44 @@ class Bot(TelegramObject):
|
||||
|
||||
return result
|
||||
|
||||
@log
|
||||
def set_chat_administrator_custom_title(self,
|
||||
chat_id,
|
||||
user_id,
|
||||
custom_title,
|
||||
timeout=None,
|
||||
**kwargs):
|
||||
"""
|
||||
Use this method to set a custom title for administrators promoted by the bot in a
|
||||
supergroup. The bot must be an administrator for this to work. Returns True on success.
|
||||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username of
|
||||
the target supergroup (in the format `@supergroupusername`).
|
||||
user_id (:obj:`int`): Unique identifier of the target administrator.
|
||||
custom_title (:obj:`str`) New custom title for the administrator. It must be a string
|
||||
with len 0-16 characters, emoji are not allowed.
|
||||
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
|
||||
the read timeout from the server (instead of the one specified during creation of
|
||||
the connection pool).
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: Returns True on success.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
|
||||
"""
|
||||
url = '{0}/setChatAdministratorCustomTitle'.format(self.base_url)
|
||||
|
||||
data = {'chat_id': chat_id, 'user_id': user_id, 'custom_title': custom_title}
|
||||
data.update(kwargs)
|
||||
|
||||
result = self._request.post(url, data, timeout=timeout)
|
||||
|
||||
return result
|
||||
|
||||
@log
|
||||
def export_chat_invite_link(self, chat_id, timeout=None, **kwargs):
|
||||
"""
|
||||
@@ -3445,18 +3513,33 @@ class Bot(TelegramObject):
|
||||
chat_id,
|
||||
question,
|
||||
options,
|
||||
is_anonymous=True,
|
||||
type=Poll.REGULAR,
|
||||
allows_multiple_answers=False,
|
||||
correct_option_id=None,
|
||||
is_closed=None,
|
||||
disable_notification=None,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None,
|
||||
timeout=None,
|
||||
**kwargs):
|
||||
"""
|
||||
Use this method to send a native poll. A native poll can't be sent to a private chat.
|
||||
Use this method to send a native poll.
|
||||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target private chat.
|
||||
question (:obj:`str`): Poll question, 1-255 characters.
|
||||
options (List[:obj:`str`]): List of answer options, 2-10 strings 1-100 characters each.
|
||||
is_anonymous (:obj:`bool`, optional): True, if the poll needs to be anonymous,
|
||||
defaults to True.
|
||||
type (:obj:`str`, optional): Poll type, :attr:`telegram.Poll.QUIZ` or
|
||||
:attr:`telegram.Poll.REGULAR`, defaults to :attr:`telegram.Poll.REGULAR`.
|
||||
allows_multiple_answers (:obj:`bool`, optional): True, if the poll allows multiple
|
||||
answers, ignored for polls in quiz mode, defaults to False
|
||||
correct_option_id (:obj:`int`, optional): 0-based identifier of the correct answer
|
||||
option, required for polls in quiz mode
|
||||
is_closed (:obj:`bool`, optional): Pass True, if the poll needs to be immediately
|
||||
closed. This can be useful for poll preview.
|
||||
disable_notification (:obj:`bool`, optional): Sends the message silently. Users will
|
||||
receive a notification with no sound.
|
||||
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
|
||||
@@ -3484,6 +3567,17 @@ class Bot(TelegramObject):
|
||||
'options': options
|
||||
}
|
||||
|
||||
if not is_anonymous:
|
||||
data['is_anonymous'] = is_anonymous
|
||||
if type:
|
||||
data['type'] = type
|
||||
if allows_multiple_answers:
|
||||
data['allows_multiple_answers'] = allows_multiple_answers
|
||||
if correct_option_id is not None:
|
||||
data['correct_option_id'] = correct_option_id
|
||||
if is_closed:
|
||||
data['is_closed'] = is_closed
|
||||
|
||||
return self._message(url, data, timeout=timeout, disable_notification=disable_notification,
|
||||
reply_to_message_id=reply_to_message_id, reply_markup=reply_markup,
|
||||
**kwargs)
|
||||
@@ -3646,6 +3740,8 @@ class Bot(TelegramObject):
|
||||
"""Alias for :attr:`promote_chat_member`"""
|
||||
setChatPermissions = set_chat_permissions
|
||||
"""Alias for :attr:`set_chat_permissions`"""
|
||||
setChatAdministratorCustomTitle = set_chat_administrator_custom_title
|
||||
"""Alias for :attr:`set_chat_administrator_custom_title`"""
|
||||
exportChatInviteLink = export_chat_invite_link
|
||||
"""Alias for :attr:`export_chat_invite_link`"""
|
||||
setChatPhoto = set_chat_photo
|
||||
|
||||
@@ -36,30 +36,31 @@ class CallbackQuery(TelegramObject):
|
||||
Attributes:
|
||||
id (:obj:`str`): Unique identifier for this query.
|
||||
from_user (:class:`telegram.User`): Sender.
|
||||
chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which
|
||||
the message with the callback button was sent.
|
||||
message (:class:`telegram.Message`): Optional. Message with the callback button that
|
||||
originated the query.
|
||||
data (:obj:`str`): Optional. Data associated with the callback button.
|
||||
inline_message_id (:obj:`str`): Optional. Identifier of the message sent via the bot in
|
||||
inline mode, that originated the query.
|
||||
chat_instance (:obj:`str`): Optional. Global identifier, uniquely corresponding to the chat
|
||||
to which the message with the callback button was sent.
|
||||
data (:obj:`str`): Optional. Data associated with the callback button.
|
||||
game_short_name (:obj:`str`): Optional. Short name of a Game to be returned.
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
id (:obj:`str`): Unique identifier for this query.
|
||||
from_user (:class:`telegram.User`): Sender.
|
||||
chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which
|
||||
the message with the callback button was sent. Useful for high scores in games.
|
||||
message (:class:`telegram.Message`, optional): Message with the callback button that
|
||||
originated the query. Note that message content and message date will not be available
|
||||
if the message is too old.
|
||||
inline_message_id (:obj:`str`, optional): Identifier of the message sent via the bot in
|
||||
inline mode, that originated the query.
|
||||
chat_instance (:obj:`str`, optional): Global identifier, uniquely corresponding to the chat
|
||||
to which the message with the callback button was sent. Useful for high scores in
|
||||
games.
|
||||
data (:obj:`str`, optional): Data associated with the callback button. Be aware that a bad
|
||||
client can send arbitrary data in this field.
|
||||
inline_message_id (:obj:`str`, optional): Identifier of the message sent via the bot in
|
||||
inline mode, that originated the query.
|
||||
game_short_name (:obj:`str`, optional): Short name of a Game to be returned, serves as
|
||||
the unique identifier for the game
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
|
||||
Note:
|
||||
After the user presses an inline button, Telegram clients will display a progress bar
|
||||
|
||||
@@ -40,6 +40,8 @@ class Chat(TelegramObject):
|
||||
Returned only in get_chat.
|
||||
permissions (:class:`telegram.ChatPermission`): Optional. Default chat member permissions,
|
||||
for groups and supergroups. Returned only in getChat.
|
||||
slow_mode_delay (:obj:`int`): Optional. For supergroups, the minimum allowed delay between
|
||||
consecutive messages sent by each unpriviledged user. Returned only in getChat.
|
||||
sticker_set_name (:obj:`str`): Optional. For supergroups, name of Group sticker set.
|
||||
can_set_sticker_set (:obj:`bool`): Optional. ``True``, if the bot can change group the
|
||||
sticker set.
|
||||
@@ -65,6 +67,8 @@ class Chat(TelegramObject):
|
||||
Returned only in get_chat.
|
||||
permissions (:class:`telegram.ChatPermission`): Optional. Default chat member permissions,
|
||||
for groups and supergroups. Returned only in getChat.
|
||||
slow_mode_delay (:obj:`int`, optional): For supergroups, the minimum allowed delay between
|
||||
consecutive messages sent by each unpriviledged user. Returned only in getChat.
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
sticker_set_name (:obj:`str`, optional): For supergroups, name of Group sticker set.
|
||||
Returned only in get_chat.
|
||||
@@ -98,6 +102,7 @@ class Chat(TelegramObject):
|
||||
permissions=None,
|
||||
sticker_set_name=None,
|
||||
can_set_sticker_set=None,
|
||||
slow_mode_delay=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.id = int(id)
|
||||
@@ -114,6 +119,7 @@ class Chat(TelegramObject):
|
||||
self.invite_link = invite_link
|
||||
self.pinned_message = pinned_message
|
||||
self.permissions = permissions
|
||||
self.slow_mode_delay = slow_mode_delay
|
||||
self.sticker_set_name = sticker_set_name
|
||||
self.can_set_sticker_set = can_set_sticker_set
|
||||
|
||||
@@ -240,6 +246,17 @@ class Chat(TelegramObject):
|
||||
"""
|
||||
return self.bot.set_chat_permissions(self.id, *args, **kwargs)
|
||||
|
||||
def set_administrator_custom_title(self, *args, **kwargs):
|
||||
"""Shortcut for::
|
||||
|
||||
bot.set_chat_administrator_custom_title(update.message.chat.id, *args, **kwargs)
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: If the action was sent successfully.
|
||||
|
||||
"""
|
||||
return self.bot.set_chat_administrator_custom_title(self.id, *args, **kwargs)
|
||||
|
||||
def send_message(self, *args, **kwargs):
|
||||
"""Shortcut for::
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ class ChatMember(TelegramObject):
|
||||
Attributes:
|
||||
user (:class:`telegram.User`): Information about the user.
|
||||
status (:obj:`str`): The member's status in the chat.
|
||||
custom_title (:obj:`str`): Optional. Custom title for owner and administrators.
|
||||
until_date (:class:`datetime.datetime`): Optional. Date when restrictions will be lifted
|
||||
for this user.
|
||||
can_be_edited (:obj:`bool`): Optional. If the bot is allowed to edit administrator
|
||||
@@ -62,6 +63,8 @@ class ChatMember(TelegramObject):
|
||||
user (:class:`telegram.User`): Information about the user.
|
||||
status (:obj:`str`): The member's status in the chat. Can be 'creator', 'administrator',
|
||||
'member', 'restricted', 'left' or 'kicked'.
|
||||
custom_title (:obj:`str`, optional): Owner and administrators only.
|
||||
Custom title for this user.
|
||||
until_date (:class:`datetime.datetime`, optional): Restricted and kicked only. Date when
|
||||
restrictions will be lifted for this user.
|
||||
can_be_edited (:obj:`bool`, optional): Administrators only. True, if the bot is allowed to
|
||||
@@ -118,10 +121,11 @@ class ChatMember(TelegramObject):
|
||||
can_restrict_members=None, can_pin_messages=None,
|
||||
can_promote_members=None, can_send_messages=None,
|
||||
can_send_media_messages=None, can_send_polls=None, can_send_other_messages=None,
|
||||
can_add_web_page_previews=None, is_member=None, **kwargs):
|
||||
can_add_web_page_previews=None, is_member=None, custom_title=None, **kwargs):
|
||||
# Required
|
||||
self.user = user
|
||||
self.status = status
|
||||
self.custom_title = custom_title
|
||||
self.until_date = until_date
|
||||
self.can_be_edited = can_be_edited
|
||||
self.can_change_info = can_change_info
|
||||
|
||||
@@ -24,6 +24,11 @@ from telegram import TelegramObject
|
||||
class ChatPermissions(TelegramObject):
|
||||
"""Describes actions that a non-administrator user is allowed to take in a chat.
|
||||
|
||||
Note:
|
||||
Though not stated explicitly in the offical docs, Telegram changes not only the permissions
|
||||
that are set, but also sets all the others to :obj:`False`. However, since not documented,
|
||||
this behaviour may change unbeknown to PTB.
|
||||
|
||||
Attributes:
|
||||
can_send_messages (:obj:`bool`): Optional. True, if the user is allowed to send text
|
||||
messages, contacts, locations and venues.
|
||||
|
||||
@@ -41,6 +41,8 @@ from .precheckoutqueryhandler import PreCheckoutQueryHandler
|
||||
from .shippingqueryhandler import ShippingQueryHandler
|
||||
from .messagequeue import MessageQueue
|
||||
from .messagequeue import DelayQueue
|
||||
from .pollanswerhandler import PollAnswerHandler
|
||||
from .pollhandler import PollHandler
|
||||
from .defaults import Defaults
|
||||
|
||||
__all__ = ('Dispatcher', 'JobQueue', 'Job', 'Updater', 'CallbackQueryHandler',
|
||||
@@ -49,4 +51,5 @@ __all__ = ('Dispatcher', 'JobQueue', 'Job', 'Updater', 'CallbackQueryHandler',
|
||||
'StringRegexHandler', 'TypeHandler', 'ConversationHandler',
|
||||
'PreCheckoutQueryHandler', 'ShippingQueryHandler', 'MessageQueue', 'DelayQueue',
|
||||
'DispatcherHandlerStop', 'run_async', 'CallbackContext', 'BasePersistence',
|
||||
'PicklePersistence', 'DictPersistence', 'PrefixHandler', 'Defaults')
|
||||
'PicklePersistence', 'DictPersistence', 'PrefixHandler', 'PollAnswerHandler',
|
||||
'PollHandler', 'Defaults')
|
||||
|
||||
@@ -93,10 +93,10 @@ class ConversationHandler(Handler):
|
||||
per_user (:obj:`bool`): If the conversationkey should contain the User's ID.
|
||||
per_message (:obj:`bool`): If the conversationkey should contain the Message's
|
||||
ID.
|
||||
conversation_timeout (:obj:`float`|:obj:`datetime.timedelta`): Optional. When this handler
|
||||
is inactive more than this timeout (in seconds), it will be automatically ended. If
|
||||
this value is 0 (default), there will be no timeout. When it's triggered, the last
|
||||
received update will be handled by ALL the handler's who's `check_update` method
|
||||
conversation_timeout (:obj:`float` | :obj:`datetime.timedelta`): Optional. When this
|
||||
handler is inactive more than this timeout (in seconds), it will be automatically
|
||||
ended. If this value is 0 (default), there will be no timeout. When it's triggered, the
|
||||
last received update will be handled by ALL the handler's who's `check_update` method
|
||||
returns True that are in the state :attr:`ConversationHandler.TIMEOUT`.
|
||||
name (:obj:`str`): Optional. The name for this conversationhandler. Required for
|
||||
persistence
|
||||
|
||||
@@ -81,12 +81,12 @@ class PicklePersistence(BasePersistence):
|
||||
try:
|
||||
filename = self.filename
|
||||
with open(self.filename, "rb") as f:
|
||||
all = pickle.load(f)
|
||||
self.user_data = defaultdict(dict, all['user_data'])
|
||||
self.chat_data = defaultdict(dict, all['chat_data'])
|
||||
data = pickle.load(f)
|
||||
self.user_data = defaultdict(dict, data['user_data'])
|
||||
self.chat_data = defaultdict(dict, data['chat_data'])
|
||||
# For backwards compatibility with files not containing bot data
|
||||
self.bot_data = all.get('bot_data', {})
|
||||
self.conversations = all['conversations']
|
||||
self.bot_data = data.get('bot_data', {})
|
||||
self.conversations = data['conversations']
|
||||
except IOError:
|
||||
self.conversations = {}
|
||||
self.user_data = defaultdict(dict)
|
||||
@@ -110,9 +110,9 @@ class PicklePersistence(BasePersistence):
|
||||
|
||||
def dump_singlefile(self):
|
||||
with open(self.filename, "wb") as f:
|
||||
all = {'conversations': self.conversations, 'user_data': self.user_data,
|
||||
'chat_data': self.chat_data, 'bot_data': self.bot_data}
|
||||
pickle.dump(all, f)
|
||||
data = {'conversations': self.conversations, 'user_data': self.user_data,
|
||||
'chat_data': self.chat_data, 'bot_data': self.bot_data}
|
||||
pickle.dump(data, f)
|
||||
|
||||
def dump_file(self, filename, data):
|
||||
with open(filename, "wb") as f:
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2019
|
||||
# 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/].
|
||||
|
||||
from telegram import Update
|
||||
from .handler import Handler
|
||||
|
||||
|
||||
class PollAnswerHandler(Handler):
|
||||
"""Handler class to handle Telegram updates that contain a poll answer.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
either the user or the chat that the update was sent in. For each update from the same user
|
||||
or in the same chat, it will be the same ``dict``.
|
||||
|
||||
Note that this is DEPRECATED, and you should use context based callbacks. See
|
||||
https://git.io/fxJuV for more info.
|
||||
|
||||
Args:
|
||||
callback (:obj:`callable`): The callback function for this handler. Will be called when
|
||||
:attr:`check_update` has determined that an update should be processed by this handler.
|
||||
Callback signature for context based API:
|
||||
|
||||
``def callback(update: Update, context: CallbackContext)``
|
||||
|
||||
The return value of the callback is usually ignored except for the special case of
|
||||
:class:`telegram.ext.ConversationHandler`.
|
||||
pass_update_queue (:obj:`bool`, optional): If set to ``True``, a keyword argument called
|
||||
``update_queue`` will be passed to the callback function. It will be the ``Queue``
|
||||
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
|
||||
that contains new updates which can be used to insert updates. Default is ``False``.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
pass_job_queue (:obj:`bool`, optional): If set to ``True``, a keyword argument called
|
||||
``job_queue`` will be passed to the callback function. It will be a
|
||||
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
|
||||
which can be used to schedule new jobs. Default is ``False``.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
pass_user_data (:obj:`bool`, optional): If set to ``True``, a keyword argument called
|
||||
``user_data`` will be passed to the callback function. Default is ``False``.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
pass_chat_data (:obj:`bool`, optional): If set to ``True``, a keyword argument called
|
||||
``chat_data`` will be passed to the callback function. Default is ``False``.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
|
||||
"""
|
||||
|
||||
def check_update(self, update):
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
"""
|
||||
return isinstance(update, Update) and update.poll_answer
|
||||
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2019
|
||||
# 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/].
|
||||
|
||||
from telegram import Update
|
||||
from .handler import Handler
|
||||
|
||||
|
||||
class PollHandler(Handler):
|
||||
"""Handler class to handle Telegram updates that contain a poll.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
either the user or the chat that the update was sent in. For each update from the same user
|
||||
or in the same chat, it will be the same ``dict``.
|
||||
|
||||
Note that this is DEPRECATED, and you should use context based callbacks. See
|
||||
https://git.io/fxJuV for more info.
|
||||
|
||||
Args:
|
||||
callback (:obj:`callable`): The callback function for this handler. Will be called when
|
||||
:attr:`check_update` has determined that an update should be processed by this handler.
|
||||
Callback signature for context based API:
|
||||
|
||||
``def callback(update: Update, context: CallbackContext)``
|
||||
|
||||
The return value of the callback is usually ignored except for the special case of
|
||||
:class:`telegram.ext.ConversationHandler`.
|
||||
pass_update_queue (:obj:`bool`, optional): If set to ``True``, a keyword argument called
|
||||
``update_queue`` will be passed to the callback function. It will be the ``Queue``
|
||||
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
|
||||
that contains new updates which can be used to insert updates. Default is ``False``.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
pass_job_queue (:obj:`bool`, optional): If set to ``True``, a keyword argument called
|
||||
``job_queue`` will be passed to the callback function. It will be a
|
||||
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
|
||||
which can be used to schedule new jobs. Default is ``False``.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
pass_user_data (:obj:`bool`, optional): If set to ``True``, a keyword argument called
|
||||
``user_data`` will be passed to the callback function. Default is ``False``.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
pass_chat_data (:obj:`bool`, optional): If set to ``True``, a keyword argument called
|
||||
``chat_data`` will be passed to the callback function. Default is ``False``.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
|
||||
"""
|
||||
|
||||
def check_update(self, update):
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
"""
|
||||
return isinstance(update, Update) and update.poll
|
||||
@@ -91,7 +91,9 @@ class Updater(object):
|
||||
be used if not set explicitly in the bot methods.
|
||||
|
||||
Note:
|
||||
You must supply either a :attr:`bot` or a :attr:`token` argument.
|
||||
* You must supply either a :attr:`bot` or a :attr:`token` argument.
|
||||
* If you supply a :attr:`bot`, you will need to pass :attr:`defaults` to *both* the bot and
|
||||
the :class:`telegram.ext.Updater`.
|
||||
|
||||
Raises:
|
||||
ValueError: If both :attr:`token` and :attr:`bot` are passed or none of them.
|
||||
|
||||
@@ -25,7 +25,10 @@ class Animation(TelegramObject):
|
||||
"""This object represents an animation file to be displayed in the message containing a game.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Unique file identifier.
|
||||
file_id (:obj:`str`): File identifier.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
width (:obj:`int`): Video width as defined by sender.
|
||||
height (:obj:`int`): Video height as defined by sender.
|
||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
||||
@@ -37,7 +40,10 @@ class Animation(TelegramObject):
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Unique file identifier.
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
file_unique_id (:obj:`str`): Unique and the same over time and
|
||||
for different bots file identifier.
|
||||
width (:obj:`int`): Video width as defined by sender.
|
||||
height (:obj:`int`): Video height as defined by sender.
|
||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
||||
@@ -52,6 +58,7 @@ class Animation(TelegramObject):
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
width,
|
||||
height,
|
||||
duration,
|
||||
@@ -63,6 +70,7 @@ class Animation(TelegramObject):
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
self.width = int(width)
|
||||
self.height = int(height)
|
||||
self.duration = duration
|
||||
@@ -73,7 +81,7 @@ class Animation(TelegramObject):
|
||||
self.file_size = file_size
|
||||
self.bot = bot
|
||||
|
||||
self._id_attrs = (self.file_id,)
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
|
||||
+10
-2
@@ -26,6 +26,9 @@ class Audio(TelegramObject):
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
duration (:obj:`int`): Duration of the audio in seconds.
|
||||
performer (:obj:`str`): Optional. Performer of the audio as defined by sender or by audio
|
||||
tags.
|
||||
@@ -37,7 +40,10 @@ class Audio(TelegramObject):
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
file_unique_id (:obj:`str`): Unique and the same over time and
|
||||
for different bots file identifier.
|
||||
duration (:obj:`int`): Duration of the audio in seconds as defined by sender.
|
||||
performer (:obj:`str`, optional): Performer of the audio as defined by sender or by audio
|
||||
tags.
|
||||
@@ -53,6 +59,7 @@ class Audio(TelegramObject):
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
duration,
|
||||
performer=None,
|
||||
title=None,
|
||||
@@ -63,6 +70,7 @@ class Audio(TelegramObject):
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
self.duration = int(duration)
|
||||
# Optionals
|
||||
self.performer = performer
|
||||
@@ -72,7 +80,7 @@ class Audio(TelegramObject):
|
||||
self.thumb = thumb
|
||||
self.bot = bot
|
||||
|
||||
self._id_attrs = (self.file_id,)
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
|
||||
@@ -25,24 +25,48 @@ class ChatPhoto(TelegramObject):
|
||||
|
||||
Attributes:
|
||||
small_file_id (:obj:`str`): File identifier of small (160x160) chat photo.
|
||||
This file_id can be used only for photo download and only for as long
|
||||
as the photo is not changed.
|
||||
small_file_unique_id (:obj:`str`): Unique file identifier of small (160x160) chat photo,
|
||||
which is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
big_file_id (:obj:`str`): File identifier of big (640x640) chat photo.
|
||||
|
||||
This file_id can be used only for photo download and only for as long as
|
||||
the photo is not changed.
|
||||
big_file_unique_id (:obj:`str`): Unique file identifier of big (640x640) chat photo,
|
||||
which is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
Args:
|
||||
small_file_id (:obj:`str`): File identifier of small (160x160) chat photo. This file_id can
|
||||
be used only for photo download and only for as long as the photo is not changed.
|
||||
big_file_id (:obj:`str`): File identifier of big (640x640) chat photo. This file_id can be
|
||||
used only for photo download and only for as long as the photo is not changed.
|
||||
small_file_id (:obj:`str`): Unique file identifier of small (160x160) chat photo. This
|
||||
file_id can be used only for photo download and only for as long
|
||||
as the photo is not changed.
|
||||
small_file_unique_id (:obj:`str`): Unique file identifier of small (160x160) chat photo,
|
||||
which is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
big_file_id (:obj:`str`): Unique file identifier of big (640x640) chat photo. This file_id
|
||||
can be used only for photo download and only for as long as the photo is not changed.
|
||||
big_file_unique_id (:obj:`str`): Unique file identifier of big (640x640) chat photo,
|
||||
which is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, small_file_id, big_file_id, bot=None, **kwargs):
|
||||
def __init__(self,
|
||||
small_file_id,
|
||||
small_file_unique_id,
|
||||
big_file_id,
|
||||
big_file_unique_id,
|
||||
bot=None, **kwargs):
|
||||
self.small_file_id = small_file_id
|
||||
self.small_file_unique_id = small_file_unique_id
|
||||
self.big_file_id = big_file_id
|
||||
self.big_file_unique_id = big_file_unique_id
|
||||
|
||||
self.bot = bot
|
||||
|
||||
self._id_attrs = (self.small_file_id, self.big_file_id)
|
||||
self._id_attrs = (self.small_file_unique_id, self.big_file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
|
||||
@@ -26,6 +26,9 @@ class Document(TelegramObject):
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Unique file identifier.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
thumb (:class:`telegram.PhotoSize`): Optional. Document thumbnail.
|
||||
file_name (:obj:`str`): Original filename.
|
||||
mime_type (:obj:`str`): Optional. MIME type of the file.
|
||||
@@ -33,7 +36,10 @@ class Document(TelegramObject):
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Unique file identifier
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
file_unique_id (:obj:`str`): Unique and the same over time and
|
||||
for different bots file identifier.
|
||||
thumb (:class:`telegram.PhotoSize`, optional): Document thumbnail as defined by sender.
|
||||
file_name (:obj:`str`, optional): Original filename as defined by sender.
|
||||
mime_type (:obj:`str`, optional): MIME type of the file as defined by sender.
|
||||
@@ -46,6 +52,7 @@ class Document(TelegramObject):
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
thumb=None,
|
||||
file_name=None,
|
||||
mime_type=None,
|
||||
@@ -54,6 +61,7 @@ class Document(TelegramObject):
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
# Optionals
|
||||
self.thumb = thumb
|
||||
self.file_name = file_name
|
||||
@@ -61,7 +69,7 @@ class Document(TelegramObject):
|
||||
self.file_size = file_size
|
||||
self.bot = bot
|
||||
|
||||
self._id_attrs = (self.file_id,)
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
|
||||
+16
-5
@@ -38,11 +38,17 @@ class File(TelegramObject):
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
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:`str`): Optional. File size.
|
||||
file_path (:obj:`str`): Optional. File path. Use :attr:`download` to get the file.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
file_unique_id (:obj:`str`): Unique and the same over time and
|
||||
for different bots file identifier.
|
||||
file_size (:obj:`int`, optional): Optional. File size, if known.
|
||||
file_path (:obj:`str`, optional): File path. Use :attr:`download` to get the file.
|
||||
bot (:obj:`telegram.Bot`, optional): Bot to use with shortcut method.
|
||||
@@ -54,18 +60,23 @@ class File(TelegramObject):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, file_id, bot=None, file_size=None, file_path=None, **kwargs):
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
bot=None,
|
||||
file_size=None,
|
||||
file_path=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
# Optionals
|
||||
self.file_size = file_size
|
||||
self.file_path = file_path
|
||||
|
||||
self.bot = bot
|
||||
self._credentials = None
|
||||
|
||||
self._id_attrs = (self.file_id,)
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
|
||||
@@ -47,7 +47,8 @@ class InputMediaAnimation(InputMedia):
|
||||
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
|
||||
A thumbnail's width and height should not exceed 320. Ignored if the file is not
|
||||
is passed as a string or file_id.
|
||||
caption (:obj:`str`): Optional. Caption of the animation to be sent, 0-1024 characters.
|
||||
caption (:obj:`str`): Optional. Caption of the animation to be sent, 0-1024 characters
|
||||
after entities parsing.
|
||||
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -64,7 +65,8 @@ class InputMediaAnimation(InputMedia):
|
||||
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
|
||||
A thumbnail's width and height should not exceed 320. Ignored if the file is not
|
||||
is passed as a string or file_id.
|
||||
caption (:obj:`str`, optional): Caption of the animation to be sent, 0-1024 characters.
|
||||
caption (:obj:`str`, optional): Caption of the animation to be sent, 0-1024 characters
|
||||
after entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -124,7 +126,8 @@ class InputMediaPhoto(InputMedia):
|
||||
(recommended), pass an HTTP URL as a String for Telegram to get a photo from the
|
||||
Internet, or upload a new photo using multipart/form-data. Lastly you can pass
|
||||
an existing :class:`telegram.PhotoSize` object to send.
|
||||
caption (:obj:`str`): Optional. Caption of the photo to be sent, 0-1024 characters.
|
||||
caption (:obj:`str`): Optional. Caption of the photo to be sent, 0-1024 characters after
|
||||
entities parsing.
|
||||
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -133,7 +136,8 @@ class InputMediaPhoto(InputMedia):
|
||||
media (:obj:`str`): File to send. Pass a file_id to send a file that exists on the
|
||||
Telegram servers (recommended), pass an HTTP URL for Telegram to get a file from the
|
||||
Internet. Lastly you can pass an existing :class:`telegram.PhotoSize` object to send.
|
||||
caption (:obj:`str`, optional ): Caption of the photo to be sent, 0-1024 characters.
|
||||
caption (:obj:`str`, optional ): Caption of the photo to be sent, 0-1024 characters after
|
||||
entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -164,7 +168,8 @@ class InputMediaVideo(InputMedia):
|
||||
(recommended), pass an HTTP URL as a String for Telegram to get an video file from
|
||||
the Internet, or upload a new one using multipart/form-data. Lastly you can pass
|
||||
an existing :class:`telegram.Video` object to send.
|
||||
caption (:obj:`str`): Optional. Caption of the video to be sent, 0-1024 characters.
|
||||
caption (:obj:`str`): Optional. Caption of the video to be sent, 0-1024 characters after
|
||||
entities parsing.
|
||||
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -182,7 +187,8 @@ class InputMediaVideo(InputMedia):
|
||||
media (:obj:`str`): File to send. Pass a file_id to send a file that exists on the Telegram
|
||||
servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet.
|
||||
Lastly you can pass an existing :class:`telegram.Video` object to send.
|
||||
caption (:obj:`str`, optional): Caption of the video to be sent, 0-1024 characters.
|
||||
caption (:obj:`str`, optional): Caption of the video to be sent, 0-1024 characters after
|
||||
entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -244,7 +250,8 @@ class InputMediaAudio(InputMedia):
|
||||
(recommended), pass an HTTP URL as a String for Telegram to get an audio file from
|
||||
the Internet, or upload a new one using multipart/form-data. Lastly you can pass
|
||||
an existing :class:`telegram.Audio` object to send.
|
||||
caption (:obj:`str`): Optional. Caption of the audio to be sent, 0-1024 characters.
|
||||
caption (:obj:`str`): Optional. Caption of the audio to be sent, 0-1024 characters after
|
||||
entities parsing.
|
||||
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -261,7 +268,8 @@ class InputMediaAudio(InputMedia):
|
||||
media (:obj:`str`): File to send. Pass a file_id to send a file that exists on the Telegram
|
||||
servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet.
|
||||
Lastly you can pass an existing :class:`telegram.Document` object to send.
|
||||
caption (:obj:`str`, optional): Caption of the audio to be sent, 0-1024 characters.
|
||||
caption (:obj:`str`, optional): Caption of the audio to be sent, 0-1024 characters after
|
||||
entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -320,7 +328,8 @@ class InputMediaDocument(InputMedia):
|
||||
(recommended), pass an HTTP URL as a String for Telegram to get a file from the
|
||||
Internet, or upload a new one using multipart/form-data. Lastly you can pass
|
||||
an existing :class:`telegram.Document` object to send.
|
||||
caption (:obj:`str`): Optional. Caption of the document to be sent, 0-1024 characters.
|
||||
caption (:obj:`str`): Optional. Caption of the document to be sent, 0-1024 characters after
|
||||
entities parsing.
|
||||
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -333,7 +342,8 @@ class InputMediaDocument(InputMedia):
|
||||
media (:obj:`str`): File to send. Pass a file_id to send a file that exists on the Telegram
|
||||
servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet.
|
||||
Lastly you can pass an existing :class:`telegram.Document` object to send.
|
||||
caption (:obj:`str`, optional): Caption of the document to be sent, 0-1024 characters.
|
||||
caption (:obj:`str`, optional): Caption of the document to be sent, 0-1024 characters after
|
||||
entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
|
||||
@@ -26,13 +26,19 @@ class PhotoSize(TelegramObject):
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
width (:obj:`int`): Photo width.
|
||||
height (:obj:`int`): Photo height.
|
||||
file_size (:obj:`int`): Optional. File size.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
file_unique_id (:obj:`str`): Unique and the same over time and
|
||||
for different bots file identifier.
|
||||
width (:obj:`int`): Photo width.
|
||||
height (:obj:`int`): Photo height.
|
||||
file_size (:obj:`int`, optional): File size.
|
||||
@@ -41,16 +47,24 @@ class PhotoSize(TelegramObject):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, file_id, width, height, file_size=None, bot=None, **kwargs):
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
width,
|
||||
height,
|
||||
file_size=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
self.width = int(width)
|
||||
self.height = int(height)
|
||||
# Optionals
|
||||
self.file_size = file_size
|
||||
self.bot = bot
|
||||
|
||||
self._id_attrs = (self.file_id,)
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
|
||||
@@ -26,6 +26,9 @@ class Sticker(TelegramObject):
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
width (:obj:`int`): Sticker width.
|
||||
height (:obj:`int`): Sticker height.
|
||||
is_animated (:obj:`bool`): True, if the sticker is animated.
|
||||
@@ -39,7 +42,10 @@ class Sticker(TelegramObject):
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
file_unique_id (:obj:`str`): Unique and the same over time and
|
||||
for different bots file identifier.
|
||||
width (:obj:`int`): Sticker width.
|
||||
height (:obj:`int`): Sticker height.
|
||||
is_animated (:obj:`bool`): True, if the sticker is animated.
|
||||
@@ -58,6 +64,7 @@ class Sticker(TelegramObject):
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
width,
|
||||
height,
|
||||
is_animated,
|
||||
@@ -70,6 +77,7 @@ class Sticker(TelegramObject):
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
self.width = int(width)
|
||||
self.height = int(height)
|
||||
self.is_animated = is_animated
|
||||
@@ -81,7 +89,7 @@ class Sticker(TelegramObject):
|
||||
self.mask_position = mask_position
|
||||
self.bot = bot
|
||||
|
||||
self._id_attrs = (self.file_id,)
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
|
||||
+10
-2
@@ -26,6 +26,9 @@ class Video(TelegramObject):
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
width (:obj:`int`): Video width as defined by sender.
|
||||
height (:obj:`int`): Video height as defined by sender.
|
||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
||||
@@ -35,7 +38,10 @@ class Video(TelegramObject):
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
file_unique_id (:obj:`str`): Unique and the same over time and
|
||||
for different bots file identifier.
|
||||
width (:obj:`int`): Video width as defined by sender.
|
||||
height (:obj:`int`): Video height as defined by sender.
|
||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
||||
@@ -49,6 +55,7 @@ class Video(TelegramObject):
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
width,
|
||||
height,
|
||||
duration,
|
||||
@@ -59,6 +66,7 @@ class Video(TelegramObject):
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
self.width = int(width)
|
||||
self.height = int(height)
|
||||
self.duration = int(duration)
|
||||
@@ -68,7 +76,7 @@ class Video(TelegramObject):
|
||||
self.file_size = file_size
|
||||
self.bot = bot
|
||||
|
||||
self._id_attrs = (self.file_id,)
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
|
||||
@@ -26,6 +26,9 @@ class VideoNote(TelegramObject):
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
length (:obj:`int`): Video width and height as defined by sender.
|
||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
||||
thumb (:class:`telegram.PhotoSize`): Optional. Video thumbnail.
|
||||
@@ -33,7 +36,10 @@ class VideoNote(TelegramObject):
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
file_unique_id (:obj:`str`): Unique and the same over time and
|
||||
for different bots file identifier.
|
||||
length (:obj:`int`): Video width and height as defined by sender.
|
||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
||||
thumb (:class:`telegram.PhotoSize`, optional): Video thumbnail.
|
||||
@@ -43,9 +49,18 @@ class VideoNote(TelegramObject):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, file_id, length, duration, thumb=None, file_size=None, bot=None, **kwargs):
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
length,
|
||||
duration,
|
||||
thumb=None,
|
||||
file_size=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
self.length = int(length)
|
||||
self.duration = int(duration)
|
||||
# Optionals
|
||||
@@ -53,7 +68,7 @@ class VideoNote(TelegramObject):
|
||||
self.file_size = file_size
|
||||
self.bot = bot
|
||||
|
||||
self._id_attrs = (self.file_id,)
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
|
||||
+17
-3
@@ -26,13 +26,19 @@ class Voice(TelegramObject):
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
duration (:obj:`int`): Duration of the audio in seconds as defined by sender.
|
||||
mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender.
|
||||
file_size (:obj:`int`): Optional. File size.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
file_unique_id (:obj:`str`): Unique and the same over time and
|
||||
for different bots file identifier.
|
||||
duration (:obj:`int`, optional): Duration of the audio in seconds as defined by sender.
|
||||
mime_type (:obj:`str`, optional): MIME type of the file as defined by sender.
|
||||
file_size (:obj:`int`, optional): File size.
|
||||
@@ -41,16 +47,24 @@ class Voice(TelegramObject):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, file_id, duration, mime_type=None, file_size=None, bot=None, **kwargs):
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
duration,
|
||||
mime_type=None,
|
||||
file_size=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
self.duration = int(duration)
|
||||
# Optionals
|
||||
self.mime_type = mime_type
|
||||
self.file_size = file_size
|
||||
self.bot = bot
|
||||
|
||||
self._id_attrs = (self.file_id,)
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
|
||||
@@ -35,7 +35,7 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
|
||||
video_file_id (:obj:`str`): A valid file identifier for the video file.
|
||||
title (:obj:`str`): Title for the result.
|
||||
description (:obj:`str`): Optional. Short description of the result.
|
||||
caption (:obj:`str`): Optional. Caption, 0-1024 characters.
|
||||
caption (:obj:`str`): Optional. Caption, 0-1024 characters after entities parsing.
|
||||
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -49,7 +49,7 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
|
||||
video_file_id (:obj:`str`): A valid file identifier for the video file.
|
||||
title (:obj:`str`): Title for the result.
|
||||
description (:obj:`str`, optional): Short description of the result.
|
||||
caption (:obj:`str`, optional): Caption, 0-1024 characters.
|
||||
caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
|
||||
@@ -33,7 +33,7 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
|
||||
id (:obj:`str`): Unique identifier for this result, 1-64 bytes.
|
||||
voice_file_id (:obj:`str`): A valid file identifier for the voice message.
|
||||
title (:obj:`str`): Voice message title.
|
||||
caption (:obj:`str`): Optional. Caption, 0-1024 characters.
|
||||
caption (:obj:`str`): Optional. Caption, 0-1024 characters after entities parsing.
|
||||
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -46,7 +46,7 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
|
||||
id (:obj:`str`): Unique identifier for this result, 1-64 bytes.
|
||||
voice_file_id (:obj:`str`): A valid file identifier for the voice message.
|
||||
title (:obj:`str`): Voice message title.
|
||||
caption (:obj:`str`, optional): Caption, 0-1024 characters.
|
||||
caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
|
||||
@@ -55,7 +55,7 @@ class InlineQueryResultVideo(InlineQueryResult):
|
||||
mime_type (:obj:`str`): Mime type of the content of video url, "text/html" or "video/mp4".
|
||||
thumb_url (:obj:`str`): URL of the thumbnail (jpeg only) for the video.
|
||||
title (:obj:`str`): Title for the result.
|
||||
caption (:obj:`str`, optional): Caption, 0-1024 characters.
|
||||
caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
|
||||
@@ -34,7 +34,7 @@ class InlineQueryResultVoice(InlineQueryResult):
|
||||
id (:obj:`str`): Unique identifier for this result, 1-64 bytes.
|
||||
voice_url (:obj:`str`): A valid URL for the voice recording.
|
||||
title (:obj:`str`): Voice message title.
|
||||
caption (:obj:`str`): Optional. Caption, 0-1024 characters.
|
||||
caption (:obj:`str`): Optional. Caption, 0-1024 characters after entities parsing.
|
||||
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption.. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
@@ -48,7 +48,7 @@ class InlineQueryResultVoice(InlineQueryResult):
|
||||
id (:obj:`str`): Unique identifier for this result, 1-64 bytes.
|
||||
voice_url (:obj:`str`): A valid URL for the voice recording.
|
||||
title (:obj:`str`): Voice message title.
|
||||
caption (:obj:`str`, optional): Caption, 0-1024 characters.
|
||||
caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in the media caption.. See the constants
|
||||
in :class:`telegram.ParseMode` for the available modes.
|
||||
|
||||
@@ -27,15 +27,16 @@ class InputTextMessageContent(InputMessageContent):
|
||||
Represents the content of a text message to be sent as the result of an inline query.
|
||||
|
||||
Attributes:
|
||||
message_text (:obj:`str`): Text of the message to be sent, 1-4096 characters.
|
||||
message_text (:obj:`str`): Text of the message to be sent, 1-4096 characters after entities
|
||||
parsing.
|
||||
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in your bot's message.
|
||||
disable_web_page_preview (:obj:`bool`): Optional. Disables link previews for links in the
|
||||
sent message.
|
||||
|
||||
Args:
|
||||
message_text (:obj:`str`): Text of the message to be sent, 1-4096 characters. Also found
|
||||
as :attr:`telegram.constants.MAX_MESSAGE_LENGTH`.
|
||||
message_text (:obj:`str`): Text of the message to be sent, 1-4096 characters after entities
|
||||
parsing. Also found as :attr:`telegram.constants.MAX_MESSAGE_LENGTH`.
|
||||
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
|
||||
bold, italic, fixed-width text or inline URLs in your bot's message.
|
||||
disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in the
|
||||
|
||||
@@ -33,6 +33,7 @@ class KeyboardButton(TelegramObject):
|
||||
text (:obj:`str`): Text of the button.
|
||||
request_contact (:obj:`bool`): Optional. If the user's phone number will be sent.
|
||||
request_location (:obj:`bool`): Optional. If the user's current location will be sent.
|
||||
request_poll (:class:`KeyboardButtonPollType`): Optional. If the user should create a poll.
|
||||
|
||||
Args:
|
||||
text (:obj:`str`): Text of the button. If none of the optional fields are used, it will be
|
||||
@@ -41,16 +42,24 @@ class KeyboardButton(TelegramObject):
|
||||
a contact when the button is pressed. Available in private chats only.
|
||||
request_location (:obj:`bool`, optional): If True, the user's current location will be sent
|
||||
when the button is pressed. Available in private chats only.
|
||||
request_poll (:class:`KeyboardButtonPollType`, optional): If specified, the user will be
|
||||
asked to create a poll and send it to the bot when the button is pressed. Available in
|
||||
private chats only.
|
||||
|
||||
Note:
|
||||
:attr:`request_contact` and :attr:`request_location` options will only work in Telegram
|
||||
versions released after 9 April, 2016. Older clients will ignore them.
|
||||
|
||||
:attr:`request_poll` option will only work in Telegram versions released after 23 January,
|
||||
2020. Older clients will receive unsupported message.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, text, request_contact=None, request_location=None, **kwargs):
|
||||
def __init__(self, text, request_contact=None, request_location=None, request_poll=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.text = text
|
||||
# Optionals
|
||||
self.request_contact = request_contact
|
||||
self.request_location = request_location
|
||||
self.request_poll = request_poll
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=R0903
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2020
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a type of a Telegram Poll."""
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class KeyboardButtonPollType(TelegramObject):
|
||||
"""This object represents type of a poll, which is allowed to be created
|
||||
and sent when the corresponding button is pressed.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Optional. If :attr:`telegram.Poll.QUIZ` is passed, the user will be
|
||||
allowed to create only polls in the quiz mode. If :attr:`telegram.Poll.REGULAR` is
|
||||
passed, only regular polls will be allowed. Otherwise, the user will be allowed to
|
||||
create a poll of any type.
|
||||
"""
|
||||
def __init__(self, type=None):
|
||||
self.type = type
|
||||
|
||||
self._id_attrs = (self.type,)
|
||||
+277
-61
@@ -510,7 +510,7 @@ class Message(TelegramObject):
|
||||
bot.send_message(update.message.chat_id, parse_mode=ParseMode.MARKDOWN, *args,
|
||||
**kwargs)
|
||||
|
||||
Sends a message with markdown formatting.
|
||||
Sends a message with markdown version 1 formatting.
|
||||
|
||||
Keyword Args:
|
||||
quote (:obj:`bool`, optional): If set to ``True``, the message is sent as an actual
|
||||
@@ -528,6 +528,30 @@ class Message(TelegramObject):
|
||||
|
||||
return self.bot.send_message(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_markdown_v2(self, *args, **kwargs):
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_message(update.message.chat_id, parse_mode=ParseMode.MARKDOWN_V2, *args,
|
||||
**kwargs)
|
||||
|
||||
Sends a message with markdown version 2 formatting.
|
||||
|
||||
Keyword Args:
|
||||
quote (:obj:`bool`, optional): If set to ``True``, the message is sent as an actual
|
||||
reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this
|
||||
parameter will be ignored. Default: ``True`` in group chats and ``False`` in
|
||||
private chats.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, instance representing the message posted.
|
||||
"""
|
||||
|
||||
kwargs['parse_mode'] = ParseMode.MARKDOWN_V2
|
||||
|
||||
self._quote(kwargs)
|
||||
|
||||
return self.bot.send_message(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_html(self, *args, **kwargs):
|
||||
"""Shortcut for::
|
||||
|
||||
@@ -899,6 +923,22 @@ class Message(TelegramObject):
|
||||
return self.bot.delete_message(
|
||||
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
|
||||
|
||||
def stop_poll(self, *args, **kwargs):
|
||||
"""Shortcut for::
|
||||
|
||||
bot.stop_poll(chat_id=message.chat_id,
|
||||
message_id=message.message_id,
|
||||
*args,
|
||||
**kwargs)
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Poll`: On success, the stopped Poll with the
|
||||
final results is returned.
|
||||
|
||||
"""
|
||||
return self.bot.stop_poll(
|
||||
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
|
||||
|
||||
def parse_entity(self, entity):
|
||||
"""Returns the text from a given :class:`telegram.MessageEntity`.
|
||||
|
||||
@@ -1012,7 +1052,7 @@ class Message(TelegramObject):
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _parse_html(message_text, entities, urled=False):
|
||||
def _parse_html(message_text, entities, urled=False, offset=0):
|
||||
if message_text is None:
|
||||
return None
|
||||
|
||||
@@ -1022,38 +1062,78 @@ class Message(TelegramObject):
|
||||
html_text = ''
|
||||
last_offset = 0
|
||||
|
||||
for entity, text in sorted(entities.items(), key=(lambda item: item[0].offset)):
|
||||
text = escape(text)
|
||||
sorted_entities = sorted(entities.items(), key=(lambda item: item[0].offset))
|
||||
parsed_entities = []
|
||||
|
||||
if entity.type == MessageEntity.TEXT_LINK:
|
||||
insert = '<a href="{}">{}</a>'.format(entity.url, text)
|
||||
elif entity.type == MessageEntity.TEXT_MENTION and entity.user:
|
||||
insert = '<a href="tg://user?id={}">{}</a>'.format(entity.user.id, text)
|
||||
elif entity.type == MessageEntity.URL and urled:
|
||||
insert = '<a href="{0}">{0}</a>'.format(text)
|
||||
elif entity.type == MessageEntity.BOLD:
|
||||
insert = '<b>' + text + '</b>'
|
||||
elif entity.type == MessageEntity.ITALIC:
|
||||
insert = '<i>' + text + '</i>'
|
||||
elif entity.type == MessageEntity.CODE:
|
||||
insert = '<code>' + text + '</code>'
|
||||
elif entity.type == MessageEntity.PRE:
|
||||
insert = '<pre>' + text + '</pre>'
|
||||
else:
|
||||
insert = text
|
||||
for (entity, text) in sorted_entities:
|
||||
if entity not in parsed_entities:
|
||||
nested_entities = {
|
||||
e: t
|
||||
for (e, t) in sorted_entities if e.offset >= entity.offset
|
||||
and e.offset + e.length <= entity.offset + entity.length
|
||||
and e != entity
|
||||
}
|
||||
parsed_entities.extend([e for e in nested_entities.keys()])
|
||||
|
||||
text = escape(text)
|
||||
|
||||
if nested_entities:
|
||||
text = Message._parse_html(text, nested_entities,
|
||||
urled=urled, offset=entity.offset)
|
||||
|
||||
if entity.type == MessageEntity.TEXT_LINK:
|
||||
insert = '<a href="{}">{}</a>'.format(entity.url, text)
|
||||
elif entity.type == MessageEntity.TEXT_MENTION and entity.user:
|
||||
insert = '<a href="tg://user?id={}">{}</a>'.format(entity.user.id, text)
|
||||
elif entity.type == MessageEntity.URL and urled:
|
||||
insert = '<a href="{0}">{0}</a>'.format(text)
|
||||
elif entity.type == MessageEntity.BOLD:
|
||||
insert = '<b>' + text + '</b>'
|
||||
elif entity.type == MessageEntity.ITALIC:
|
||||
insert = '<i>' + text + '</i>'
|
||||
elif entity.type == MessageEntity.CODE:
|
||||
insert = '<code>' + text + '</code>'
|
||||
elif entity.type == MessageEntity.PRE:
|
||||
if entity.language:
|
||||
insert = '<pre><code class="{}">{}</code></pre>'.format(entity.language,
|
||||
text)
|
||||
else:
|
||||
insert = '<pre>' + text + '</pre>'
|
||||
elif entity.type == MessageEntity.UNDERLINE:
|
||||
insert = '<u>' + text + '</u>'
|
||||
elif entity.type == MessageEntity.STRIKETHROUGH:
|
||||
insert = '<s>' + text + '</s>'
|
||||
else:
|
||||
insert = text
|
||||
|
||||
if offset == 0:
|
||||
if sys.maxunicode == 0xffff:
|
||||
html_text += escape(message_text[last_offset:entity.offset
|
||||
- offset]) + insert
|
||||
else:
|
||||
html_text += escape(message_text[last_offset * 2:(entity.offset
|
||||
- offset) * 2]
|
||||
.decode('utf-16-le')) + insert
|
||||
else:
|
||||
if sys.maxunicode == 0xffff:
|
||||
html_text += message_text[last_offset:entity.offset - offset] + insert
|
||||
else:
|
||||
html_text += message_text[last_offset * 2:(entity.offset
|
||||
- offset) * 2].decode('utf-16-le') + insert
|
||||
|
||||
last_offset = entity.offset - offset + entity.length
|
||||
|
||||
if offset == 0:
|
||||
if sys.maxunicode == 0xffff:
|
||||
html_text += escape(message_text[last_offset:entity.offset]) + insert
|
||||
html_text += escape(message_text[last_offset:])
|
||||
else:
|
||||
html_text += escape(message_text[last_offset * 2:entity.offset * 2]
|
||||
.decode('utf-16-le')) + insert
|
||||
|
||||
last_offset = entity.offset + entity.length
|
||||
|
||||
if sys.maxunicode == 0xffff:
|
||||
html_text += escape(message_text[last_offset:])
|
||||
html_text += escape(message_text[last_offset * 2:].decode('utf-16-le'))
|
||||
else:
|
||||
html_text += escape(message_text[last_offset * 2:].decode('utf-16-le'))
|
||||
if sys.maxunicode == 0xffff:
|
||||
html_text += message_text[last_offset:]
|
||||
else:
|
||||
html_text += message_text[last_offset * 2:].decode('utf-16-le')
|
||||
|
||||
return html_text
|
||||
|
||||
@property
|
||||
@@ -1111,7 +1191,9 @@ class Message(TelegramObject):
|
||||
return self._parse_html(self.caption, self.parse_caption_entities(), urled=True)
|
||||
|
||||
@staticmethod
|
||||
def _parse_markdown(message_text, entities, urled=False):
|
||||
def _parse_markdown(message_text, entities, urled=False, version=1, offset=0):
|
||||
version = int(version)
|
||||
|
||||
if message_text is None:
|
||||
return None
|
||||
|
||||
@@ -1121,42 +1203,117 @@ class Message(TelegramObject):
|
||||
markdown_text = ''
|
||||
last_offset = 0
|
||||
|
||||
for entity, text in sorted(entities.items(), key=(lambda item: item[0].offset)):
|
||||
text = escape_markdown(text)
|
||||
sorted_entities = sorted(entities.items(), key=(lambda item: item[0].offset))
|
||||
parsed_entities = []
|
||||
|
||||
if entity.type == MessageEntity.TEXT_LINK:
|
||||
insert = '[{}]({})'.format(text, entity.url)
|
||||
elif entity.type == MessageEntity.TEXT_MENTION and entity.user:
|
||||
insert = '[{}](tg://user?id={})'.format(text, entity.user.id)
|
||||
elif entity.type == MessageEntity.URL and urled:
|
||||
insert = '[{0}]({0})'.format(text)
|
||||
elif entity.type == MessageEntity.BOLD:
|
||||
insert = '*' + text + '*'
|
||||
elif entity.type == MessageEntity.ITALIC:
|
||||
insert = '_' + text + '_'
|
||||
elif entity.type == MessageEntity.CODE:
|
||||
insert = '`' + text + '`'
|
||||
elif entity.type == MessageEntity.PRE:
|
||||
insert = '```' + text + '```'
|
||||
else:
|
||||
insert = text
|
||||
for (entity, text) in sorted_entities:
|
||||
if entity not in parsed_entities:
|
||||
nested_entities = {
|
||||
e: t
|
||||
for (e, t) in sorted_entities if e.offset >= entity.offset
|
||||
and e.offset + e.length <= entity.offset + entity.length
|
||||
and e != entity
|
||||
}
|
||||
parsed_entities.extend([e for e in nested_entities.keys()])
|
||||
|
||||
orig_text = text
|
||||
text = escape_markdown(text, version=version)
|
||||
|
||||
if nested_entities:
|
||||
if version < 2:
|
||||
raise ValueError('Nested entities are not supported for Markdown '
|
||||
'version 1')
|
||||
|
||||
text = Message._parse_markdown(text, nested_entities,
|
||||
urled=urled, offset=entity.offset,
|
||||
version=version)
|
||||
|
||||
if entity.type == MessageEntity.TEXT_LINK:
|
||||
if version == 1:
|
||||
url = entity.url
|
||||
else:
|
||||
# Links need special escaping. Also can't have entities nested within
|
||||
url = escape_markdown(entity.url, version=version,
|
||||
entity_type=MessageEntity.TEXT_LINK)
|
||||
insert = '[{}]({})'.format(text, url)
|
||||
elif entity.type == MessageEntity.TEXT_MENTION and entity.user:
|
||||
insert = '[{}](tg://user?id={})'.format(text, entity.user.id)
|
||||
elif entity.type == MessageEntity.URL and urled:
|
||||
if version == 1:
|
||||
link = orig_text
|
||||
else:
|
||||
link = text
|
||||
insert = '[{}]({})'.format(link, orig_text)
|
||||
elif entity.type == MessageEntity.BOLD:
|
||||
insert = '*' + text + '*'
|
||||
elif entity.type == MessageEntity.ITALIC:
|
||||
insert = '_' + text + '_'
|
||||
elif entity.type == MessageEntity.CODE:
|
||||
# Monospace needs special escaping. Also can't have entities nested within
|
||||
insert = '`' + escape_markdown(orig_text, version=version,
|
||||
entity_type=MessageEntity.CODE) + '`'
|
||||
elif entity.type == MessageEntity.PRE:
|
||||
# Monospace needs special escaping. Also can't have entities nested within
|
||||
code = escape_markdown(orig_text, version=version,
|
||||
entity_type=MessageEntity.PRE)
|
||||
if entity.language:
|
||||
prefix = '```' + entity.language + '\n'
|
||||
else:
|
||||
if code.startswith('\\'):
|
||||
prefix = '```'
|
||||
else:
|
||||
prefix = '```\n'
|
||||
insert = prefix + code + '```'
|
||||
elif entity.type == MessageEntity.UNDERLINE:
|
||||
if version == 1:
|
||||
raise ValueError('Underline entities are not supported for Markdown '
|
||||
'version 1')
|
||||
insert = '__' + text + '__'
|
||||
elif entity.type == MessageEntity.STRIKETHROUGH:
|
||||
if version == 1:
|
||||
raise ValueError('Strikethrough entities are not supported for Markdown '
|
||||
'version 1')
|
||||
insert = '~' + text + '~'
|
||||
else:
|
||||
insert = text
|
||||
|
||||
if offset == 0:
|
||||
if sys.maxunicode == 0xffff:
|
||||
markdown_text += escape_markdown(message_text[last_offset:entity.offset
|
||||
- offset],
|
||||
version=version) + insert
|
||||
else:
|
||||
markdown_text += escape_markdown(message_text[last_offset * 2:
|
||||
(entity.offset - offset) * 2]
|
||||
.decode('utf-16-le'),
|
||||
version=version) + insert
|
||||
else:
|
||||
if sys.maxunicode == 0xffff:
|
||||
markdown_text += message_text[last_offset:entity.offset - offset] + insert
|
||||
else:
|
||||
markdown_text += message_text[last_offset * 2:(entity.offset
|
||||
- offset) * 2].decode('utf-16-le') + insert
|
||||
|
||||
last_offset = entity.offset - offset + entity.length
|
||||
|
||||
if offset == 0:
|
||||
if sys.maxunicode == 0xffff:
|
||||
markdown_text += escape_markdown(message_text[last_offset:entity.offset]) + insert
|
||||
markdown_text += escape_markdown(message_text[last_offset:], version=version)
|
||||
else:
|
||||
markdown_text += escape_markdown(message_text[last_offset * 2:entity.offset * 2]
|
||||
.decode('utf-16-le')) + insert
|
||||
|
||||
last_offset = entity.offset + entity.length
|
||||
|
||||
if sys.maxunicode == 0xffff:
|
||||
markdown_text += escape_markdown(message_text[last_offset:])
|
||||
markdown_text += escape_markdown(message_text[last_offset * 2:]
|
||||
.decode('utf-16-le'), version=version)
|
||||
else:
|
||||
markdown_text += escape_markdown(message_text[last_offset * 2:].decode('utf-16-le'))
|
||||
if sys.maxunicode == 0xffff:
|
||||
markdown_text += message_text[last_offset:]
|
||||
else:
|
||||
markdown_text += message_text[last_offset * 2:].decode('utf-16-le')
|
||||
|
||||
return markdown_text
|
||||
|
||||
@property
|
||||
def text_markdown(self):
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message.
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message
|
||||
using :class:`telegram.ParseMode.MARKDOWN`.
|
||||
|
||||
Use this if you want to retrieve the message text with the entities formatted as Markdown
|
||||
in the same way the original message was formatted.
|
||||
@@ -1167,9 +1324,24 @@ class Message(TelegramObject):
|
||||
"""
|
||||
return self._parse_markdown(self.text, self.parse_entities(), urled=False)
|
||||
|
||||
@property
|
||||
def text_markdown_v2(self):
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message
|
||||
using :class:`telegram.ParseMode.MARKDOWN_V2`.
|
||||
|
||||
Use this if you want to retrieve the message text with the entities formatted as Markdown
|
||||
in the same way the original message was formatted.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as Markdown.
|
||||
|
||||
"""
|
||||
return self._parse_markdown(self.text, self.parse_entities(), urled=False, version=2)
|
||||
|
||||
@property
|
||||
def text_markdown_urled(self):
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message.
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message
|
||||
using :class:`telegram.ParseMode.MARKDOWN`.
|
||||
|
||||
Use this if you want to retrieve the message text with the entities formatted as Markdown.
|
||||
This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink.
|
||||
@@ -1180,10 +1352,24 @@ class Message(TelegramObject):
|
||||
"""
|
||||
return self._parse_markdown(self.text, self.parse_entities(), urled=True)
|
||||
|
||||
@property
|
||||
def text_markdown_v2_urled(self):
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message
|
||||
using :class:`telegram.ParseMode.MARKDOWN_V2`.
|
||||
|
||||
Use this if you want to retrieve the message text with the entities formatted as Markdown.
|
||||
This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as Markdown.
|
||||
|
||||
"""
|
||||
return self._parse_markdown(self.text, self.parse_entities(), urled=True, version=2)
|
||||
|
||||
@property
|
||||
def caption_markdown(self):
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message's
|
||||
caption.
|
||||
caption using :class:`telegram.ParseMode.MARKDOWN`.
|
||||
|
||||
Use this if you want to retrieve the message caption with the caption entities formatted as
|
||||
Markdown in the same way the original message was formatted.
|
||||
@@ -1194,10 +1380,25 @@ class Message(TelegramObject):
|
||||
"""
|
||||
return self._parse_markdown(self.caption, self.parse_caption_entities(), urled=False)
|
||||
|
||||
@property
|
||||
def caption_markdown_v2(self):
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message's
|
||||
caption using :class:`telegram.ParseMode.MARKDOWN_V2`.
|
||||
|
||||
Use this if you want to retrieve the message caption with the caption entities formatted as
|
||||
Markdown in the same way the original message was formatted.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as Markdown.
|
||||
|
||||
"""
|
||||
return self._parse_markdown(self.caption, self.parse_caption_entities(),
|
||||
urled=False, version=2)
|
||||
|
||||
@property
|
||||
def caption_markdown_urled(self):
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message's
|
||||
caption.
|
||||
caption using :class:`telegram.ParseMode.MARKDOWN`.
|
||||
|
||||
Use this if you want to retrieve the message caption with the caption entities formatted as
|
||||
Markdown. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink.
|
||||
@@ -1207,3 +1408,18 @@ class Message(TelegramObject):
|
||||
|
||||
"""
|
||||
return self._parse_markdown(self.caption, self.parse_caption_entities(), urled=True)
|
||||
|
||||
@property
|
||||
def caption_markdown_v2_urled(self):
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message's
|
||||
caption using :class:`telegram.ParseMode.MARKDOWN_V2`.
|
||||
|
||||
Use this if you want to retrieve the message caption with the caption entities formatted as
|
||||
Markdown. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as Markdown.
|
||||
|
||||
"""
|
||||
return self._parse_markdown(self.caption, self.parse_caption_entities(),
|
||||
urled=True, version=2)
|
||||
|
||||
@@ -32,6 +32,8 @@ class MessageEntity(TelegramObject):
|
||||
length (:obj:`int`): Length of the entity in UTF-16 code units.
|
||||
url (:obj:`str`): Optional. Url that will be opened after user taps on the text.
|
||||
user (:class:`telegram.User`): Optional. The mentioned user.
|
||||
language (:obj:`str`): Optional. Programming language of the entity
|
||||
text
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): Type of the entity. Can be mention (@username), hashtag, bot_command,
|
||||
@@ -40,13 +42,16 @@ class MessageEntity(TelegramObject):
|
||||
without usernames).
|
||||
offset (:obj:`int`): Offset in UTF-16 code units to the start of the entity.
|
||||
length (:obj:`int`): Length of the entity in UTF-16 code units.
|
||||
url (:obj:`str`, optional): For "text_link" only, url that will be opened after usertaps on
|
||||
the text.
|
||||
user (:class:`telegram.User`, optional): For "text_mention" only, the mentioned user.
|
||||
url (:obj:`str`, optional): For :attr:`TEXT_LINK` only, url that will be opened after
|
||||
usertaps on the text.
|
||||
user (:class:`telegram.User`, optional): For :attr:`TEXT_MENTION` only, the mentioned
|
||||
user.
|
||||
language (:obj:`str`, optional): For :attr:`PRE` only, the programming language of
|
||||
the entity text
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, type, offset, length, url=None, user=None, **kwargs):
|
||||
def __init__(self, type, offset, length, url=None, user=None, language=None, **kwargs):
|
||||
# Required
|
||||
self.type = type
|
||||
self.offset = offset
|
||||
@@ -54,6 +59,7 @@ class MessageEntity(TelegramObject):
|
||||
# Optionals
|
||||
self.url = url
|
||||
self.user = user
|
||||
self.language = language
|
||||
|
||||
self._id_attrs = (self.type, self.offset, self.length)
|
||||
|
||||
@@ -105,8 +111,12 @@ class MessageEntity(TelegramObject):
|
||||
""":obj:`str`: 'text_link'"""
|
||||
TEXT_MENTION = 'text_mention'
|
||||
""":obj:`str`: 'text_mention'"""
|
||||
UNDERLINE = 'underline'
|
||||
""":obj:`str`: 'underline'"""
|
||||
STRIKETHROUGH = 'strikethrough'
|
||||
""":obj:`str`: 'strikethrough'"""
|
||||
ALL_TYPES = [
|
||||
MENTION, HASHTAG, CASHTAG, PHONE_NUMBER, BOT_COMMAND, URL,
|
||||
EMAIL, BOLD, ITALIC, CODE, PRE, TEXT_LINK, TEXT_MENTION
|
||||
EMAIL, BOLD, ITALIC, CODE, PRE, TEXT_LINK, TEXT_MENTION, UNDERLINE, STRIKETHROUGH
|
||||
]
|
||||
"""List[:obj:`str`]: List of all the types."""
|
||||
|
||||
@@ -25,5 +25,7 @@ class ParseMode(object):
|
||||
|
||||
MARKDOWN = 'Markdown'
|
||||
""":obj:`str`: 'Markdown'"""
|
||||
MARKDOWN_V2 = 'MarkdownV2'
|
||||
""":obj:`str`: 'MarkdownV2'"""
|
||||
HTML = 'HTML'
|
||||
""":obj:`str`: 'HTML'"""
|
||||
|
||||
@@ -28,12 +28,18 @@ class PassportFile(TelegramObject):
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
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.
|
||||
file_date (:obj:`int`): Unix time when the file was uploaded.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Unique identifier for this file.
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
file_unique_id (:obj:`str`): Unique and the same over time and
|
||||
for different bots file identifier.
|
||||
file_size (:obj:`int`): File size.
|
||||
file_date (:obj:`int`): Unix time when the file was uploaded.
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
@@ -41,16 +47,24 @@ class PassportFile(TelegramObject):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, file_id, file_date, file_size=None, bot=None, credentials=None, **kwargs):
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
file_date,
|
||||
file_size=None,
|
||||
bot=None,
|
||||
credentials=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = file_id
|
||||
self.file_unique_id = file_unique_id
|
||||
self.file_size = file_size
|
||||
self.file_date = file_date
|
||||
# Optionals
|
||||
self.bot = bot
|
||||
self._credentials = credentials
|
||||
|
||||
self._id_attrs = (self.file_id,)
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
|
||||
+57
-2
@@ -19,7 +19,7 @@
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Poll."""
|
||||
|
||||
from telegram import (TelegramObject)
|
||||
from telegram import (TelegramObject, User)
|
||||
|
||||
|
||||
class PollOption(TelegramObject):
|
||||
@@ -48,6 +48,39 @@ class PollOption(TelegramObject):
|
||||
return cls(**data)
|
||||
|
||||
|
||||
class PollAnswer(TelegramObject):
|
||||
"""
|
||||
This object represents an answer of a user in a non-anonymous poll.
|
||||
|
||||
Attributes:
|
||||
poll_id (:obj:`str`): Unique poll identifier.
|
||||
user (:class:`telegram.User`): The user, who changed the answer to the poll.
|
||||
option_ids (List[:obj:`int`]): Identifiers of answer options, chosen by the user.
|
||||
|
||||
Args:
|
||||
poll_id (:obj:`str`): Unique poll identifier.
|
||||
user (:class:`telegram.User`): The user, who changed the answer to the poll.
|
||||
option_ids (List[:obj:`int`]): 0-based identifiers of answer options, chosen by the user.
|
||||
May be empty if the user retracted their vote.
|
||||
|
||||
"""
|
||||
def __init__(self, poll_id, user, option_ids, **kwargs):
|
||||
self.poll_id = poll_id
|
||||
self.user = user
|
||||
self.option_ids = option_ids
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super(PollAnswer, cls).de_json(data, bot)
|
||||
|
||||
data['user'] = User.de_json(data.get('user'), bot)
|
||||
|
||||
return cls(**data)
|
||||
|
||||
|
||||
class Poll(TelegramObject):
|
||||
"""
|
||||
This object contains information about a poll.
|
||||
@@ -56,21 +89,38 @@ class Poll(TelegramObject):
|
||||
id (:obj:`str`): Unique poll identifier.
|
||||
question (:obj:`str`): Poll question, 1-255 characters.
|
||||
options (List[:class:`PollOption`]): List of poll options.
|
||||
total_voter_count (:obj:`int`): Total number of users that voted in the poll.
|
||||
is_closed (:obj:`bool`): True, if the poll is closed.
|
||||
is_anonymous (:obj:`bool`): True, if the poll is anonymous.
|
||||
type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`.
|
||||
allows_multiple_answers (:obj:`bool`): True, if the poll allows multiple answers.
|
||||
correct_option_id (:obj:`int`): Optional. Identifier of the correct answer option.
|
||||
|
||||
Args:
|
||||
id (:obj:`str`): Unique poll identifier.
|
||||
question (:obj:`str`): Poll question, 1-255 characters.
|
||||
options (List[:class:`PollOption`]): List of poll options.
|
||||
is_closed (:obj:`bool`): True, if the poll is closed.
|
||||
is_anonymous (:obj:`bool`): True, if the poll is anonymous.
|
||||
type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`.
|
||||
allows_multiple_answers (:obj:`bool`): True, if the poll allows multiple answers.
|
||||
correct_option_id (:obj:`int`, optional): 0-based identifier of the correct answer option.
|
||||
Available only for polls in the quiz mode, which are closed, or was sent (not
|
||||
forwarded) by the bot or to the private chat with the bot.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, id, question, options, is_closed, **kwargs):
|
||||
def __init__(self, id, question, options, total_voter_count, is_closed, is_anonymous, type,
|
||||
allows_multiple_answers, correct_option_id=None, **kwargs):
|
||||
self.id = id
|
||||
self.question = question
|
||||
self.options = options
|
||||
self.total_voter_count = total_voter_count
|
||||
self.is_closed = is_closed
|
||||
self.is_anonymous = is_anonymous
|
||||
self.type = type
|
||||
self.allows_multiple_answers = allows_multiple_answers
|
||||
self.correct_option_id = correct_option_id
|
||||
|
||||
self._id_attrs = (self.id,)
|
||||
|
||||
@@ -91,3 +141,8 @@ class Poll(TelegramObject):
|
||||
data['options'] = [x.to_dict() for x in self.options]
|
||||
|
||||
return data
|
||||
|
||||
REGULAR = "regular"
|
||||
""":obj:`str`: 'regular'"""
|
||||
QUIZ = "quiz"
|
||||
""":obj:`str`: 'quiz'"""
|
||||
|
||||
+18
-3
@@ -20,6 +20,7 @@
|
||||
|
||||
from telegram import (Message, TelegramObject, InlineQuery, ChosenInlineResult,
|
||||
CallbackQuery, ShippingQuery, PreCheckoutQuery, Poll)
|
||||
from telegram.poll import PollAnswer
|
||||
|
||||
|
||||
class Update(TelegramObject):
|
||||
@@ -42,7 +43,10 @@ class Update(TelegramObject):
|
||||
pre_checkout_query (:class:`telegram.PreCheckoutQuery`): Optional. New incoming
|
||||
pre-checkout query.
|
||||
poll (:class:`telegram.Poll`): Optional. New poll state. Bots receive only updates
|
||||
about polls, which are sent or stopped by the bot
|
||||
about stopped polls and polls, which are sent by the bot
|
||||
poll_answer (:class:`telegram.PollAnswer`): Optional. A user changed their answer
|
||||
in a non-anonymous poll. Bots receive new votes only in polls that were sent
|
||||
by the bot itself.
|
||||
|
||||
Args:
|
||||
update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a
|
||||
@@ -67,6 +71,9 @@ class Update(TelegramObject):
|
||||
pre-checkout query. Contains full information about checkout
|
||||
poll (:class:`telegram.Poll`, optional): New poll state. Bots receive only updates
|
||||
about polls, which are sent or stopped by the bot
|
||||
poll_answer (:class:`telegram.PollAnswer`, optional): A user changed their answer
|
||||
in a non-anonymous poll. Bots receive new votes only in polls that were sent
|
||||
by the bot itself.
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
"""
|
||||
@@ -83,6 +90,7 @@ class Update(TelegramObject):
|
||||
shipping_query=None,
|
||||
pre_checkout_query=None,
|
||||
poll=None,
|
||||
poll_answer=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.update_id = int(update_id)
|
||||
@@ -97,6 +105,7 @@ class Update(TelegramObject):
|
||||
self.channel_post = channel_post
|
||||
self.edited_channel_post = edited_channel_post
|
||||
self.poll = poll
|
||||
self.poll_answer = poll_answer
|
||||
|
||||
self._effective_user = None
|
||||
self._effective_chat = None
|
||||
@@ -137,6 +146,9 @@ class Update(TelegramObject):
|
||||
elif self.pre_checkout_query:
|
||||
user = self.pre_checkout_query.from_user
|
||||
|
||||
elif self.poll_answer:
|
||||
user = self.poll_answer.user
|
||||
|
||||
self._effective_user = user
|
||||
return user
|
||||
|
||||
@@ -146,7 +158,8 @@ class Update(TelegramObject):
|
||||
:class:`telegram.Chat`: The chat that this update was sent in, no matter what kind of
|
||||
update this is. Will be ``None`` for :attr:`inline_query`,
|
||||
:attr:`chosen_inline_result`, :attr:`callback_query` from inline messages,
|
||||
:attr:`shipping_query`, :attr:`pre_checkout_query` and :attr:`poll`.
|
||||
:attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll` and
|
||||
:attr:`poll_answer`.
|
||||
|
||||
"""
|
||||
if self._effective_chat:
|
||||
@@ -178,7 +191,8 @@ class Update(TelegramObject):
|
||||
:class:`telegram.Message`: The message included in this update, no matter what kind of
|
||||
update this is. Will be ``None`` for :attr:`inline_query`,
|
||||
:attr:`chosen_inline_result`, :attr:`callback_query` from inline messages,
|
||||
:attr:`shipping_query`, :attr:`pre_checkout_query` and :attr:`poll`.
|
||||
:attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll` and
|
||||
:attr:`poll_answer`.
|
||||
|
||||
"""
|
||||
if self._effective_message:
|
||||
@@ -237,5 +251,6 @@ class Update(TelegramObject):
|
||||
edited_channel_post['default_quote'] = data.get('default_quote')
|
||||
data['edited_channel_post'] = Message.de_json(edited_channel_post, bot)
|
||||
data['poll'] = Poll.de_json(data.get('poll'), bot)
|
||||
data['poll_answer'] = PollAnswer.de_json(data.get('poll_answer'), bot)
|
||||
|
||||
return cls(**data)
|
||||
|
||||
+32
-3
@@ -34,6 +34,12 @@ class User(TelegramObject):
|
||||
last_name (:obj:`str`): Optional. User's or bot's last name.
|
||||
username (:obj:`str`): Optional. User's or bot's username.
|
||||
language_code (:obj:`str`): Optional. IETF language tag of the user's language.
|
||||
can_join_groups (:obj:`str`): Optional. True, if the bot can be invited to groups.
|
||||
Returned only in :attr:`telegram.Bot.get_me` requests.
|
||||
can_read_all_group_messages (:obj:`str`): Optional. True, if privacy mode is disabled
|
||||
for the bot. Returned only in :attr:`telegram.Bot.get_me` requests.
|
||||
supports_inline_queries (:obj:`str`): Optional. True, if the bot supports inline queries.
|
||||
Returned only in :attr:`telegram.Bot.get_me` requests.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
@@ -43,6 +49,12 @@ class User(TelegramObject):
|
||||
last_name (:obj:`str`, optional): User's or bot's last name.
|
||||
username (:obj:`str`, optional): User's or bot's username.
|
||||
language_code (:obj:`str`, optional): IETF language tag of the user's language.
|
||||
can_join_groups (:obj:`str`, optional): True, if the bot can be invited to groups.
|
||||
Returned only in :attr:`telegram.Bot.get_me` requests.
|
||||
can_read_all_group_messages (:obj:`str`, optional): True, if privacy mode is disabled
|
||||
for the bot. Returned only in :attr:`telegram.Bot.get_me` requests.
|
||||
supports_inline_queries (:obj:`str`, optional): True, if the bot supports inline queries.
|
||||
Returned only in :attr:`telegram.Bot.get_me` requests.
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
|
||||
"""
|
||||
@@ -54,6 +66,9 @@ class User(TelegramObject):
|
||||
last_name=None,
|
||||
username=None,
|
||||
language_code=None,
|
||||
can_join_groups=None,
|
||||
can_read_all_group_messages=None,
|
||||
supports_inline_queries=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
@@ -64,7 +79,9 @@ class User(TelegramObject):
|
||||
self.last_name = last_name
|
||||
self.username = username
|
||||
self.language_code = language_code
|
||||
|
||||
self.can_join_groups = can_join_groups
|
||||
self.can_read_all_group_messages = can_read_all_group_messages
|
||||
self.supports_inline_queries = supports_inline_queries
|
||||
self.bot = bot
|
||||
|
||||
self._id_attrs = (self.id,)
|
||||
@@ -99,7 +116,6 @@ class User(TelegramObject):
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super(User, cls).de_json(data, bot)
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
@@ -131,13 +147,26 @@ class User(TelegramObject):
|
||||
name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: The inline mention for the user as markdown.
|
||||
:obj:`str`: The inline mention for the user as markdown (version 1).
|
||||
|
||||
"""
|
||||
if name:
|
||||
return util_mention_markdown(self.id, name)
|
||||
return util_mention_markdown(self.id, self.full_name)
|
||||
|
||||
def mention_markdown_v2(self, name=None):
|
||||
"""
|
||||
Args:
|
||||
name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: The inline mention for the user as markdown (version 2).
|
||||
|
||||
"""
|
||||
if name:
|
||||
return util_mention_markdown(self.id, name, version=2)
|
||||
return util_mention_markdown(self.id, self.full_name, version=2)
|
||||
|
||||
def mention_html(self, name=None):
|
||||
"""
|
||||
Args:
|
||||
|
||||
@@ -44,9 +44,31 @@ def get_signal_name(signum):
|
||||
return _signames[signum]
|
||||
|
||||
|
||||
def escape_markdown(text):
|
||||
"""Helper function to escape telegram markup symbols."""
|
||||
escape_chars = '\*_`\['
|
||||
def escape_markdown(text, version=1, entity_type=None):
|
||||
"""
|
||||
Helper function to escape telegram markup symbols.
|
||||
|
||||
Args:
|
||||
text (:obj:`str`): The text.
|
||||
version (:obj:`int` | :obj:`str`): Use to specify the version of telegrams Markdown.
|
||||
Either ``1`` or ``2``. Defaults to ``1``.
|
||||
entity_type (:obj:`str`, optional): For the entity types ``PRE``, ``CODE`` and the link
|
||||
part of ``TEXT_LINKS``, only certain characters need to be escaped in ``MarkdownV2``.
|
||||
See the official API documentation for details. Only valid in combination with
|
||||
``version=2``, will be ignored else.
|
||||
"""
|
||||
if int(version) == 1:
|
||||
escape_chars = '\*_`\['
|
||||
elif int(version) == 2:
|
||||
if entity_type == 'pre' or entity_type == 'code':
|
||||
escape_chars = '`\\\\'
|
||||
elif entity_type == 'text_link':
|
||||
escape_chars = ')\\\\'
|
||||
else:
|
||||
escape_chars = '_*\[\]()~`>\#\+\-=|{}\.!'
|
||||
else:
|
||||
raise ValueError('Markdown version musst be either 1 or 2!')
|
||||
|
||||
return re.sub(r'([%s])' % escape_chars, r'\\\1', text)
|
||||
|
||||
|
||||
@@ -207,17 +229,19 @@ def mention_html(user_id, name):
|
||||
return u'<a href="tg://user?id={}">{}</a>'.format(user_id, escape(name))
|
||||
|
||||
|
||||
def mention_markdown(user_id, name):
|
||||
def mention_markdown(user_id, name, version=1):
|
||||
"""
|
||||
Args:
|
||||
user_id (:obj:`int`) The user's id which you want to mention.
|
||||
name (:obj:`str`) The name the mention is showing.
|
||||
version (:obj:`int` | :obj:`str`): Use to specify the version of telegrams Markdown.
|
||||
Either ``1`` or ``2``. Defaults to ``1``
|
||||
|
||||
Returns:
|
||||
:obj:`str`: The inline mention for the user as markdown.
|
||||
"""
|
||||
if isinstance(user_id, int):
|
||||
return u'[{}](tg://user?id={})'.format(escape_markdown(name), user_id)
|
||||
return u'[{}](tg://user?id={})'.format(escape_markdown(name, version=version), user_id)
|
||||
|
||||
|
||||
def effective_message_type(entity):
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import sys
|
||||
import logging
|
||||
from telegram import Update
|
||||
from future.utils import bytes_to_native_str
|
||||
@@ -27,7 +28,6 @@ except ImportError:
|
||||
from tornado.httpserver import HTTPServer
|
||||
from tornado.ioloop import IOLoop
|
||||
import tornado.web
|
||||
import tornado.iostream
|
||||
|
||||
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
||||
|
||||
@@ -91,6 +91,35 @@ class WebhookHandler(tornado.web.RequestHandler):
|
||||
def __init__(self, application, request, **kwargs):
|
||||
super(WebhookHandler, self).__init__(application, request, **kwargs)
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self._init_asyncio_patch()
|
||||
|
||||
def _init_asyncio_patch(self):
|
||||
"""set default asyncio policy to be compatible with tornado
|
||||
Tornado 6 (at least) is not compatible with the default
|
||||
asyncio implementation on Windows
|
||||
Pick the older SelectorEventLoopPolicy on Windows
|
||||
if the known-incompatible default policy is in use.
|
||||
do this as early as possible to make it a low priority and overrideable
|
||||
ref: https://github.com/tornadoweb/tornado/issues/2608
|
||||
TODO: if/when tornado supports the defaults in asyncio,
|
||||
remove and bump tornado requirement for py38
|
||||
Copied from https://github.com/ipython/ipykernel/pull/456/
|
||||
"""
|
||||
if sys.platform.startswith("win") and sys.version_info >= (3, 8):
|
||||
import asyncio
|
||||
try:
|
||||
from asyncio import (
|
||||
WindowsProactorEventLoopPolicy,
|
||||
WindowsSelectorEventLoopPolicy,
|
||||
)
|
||||
except ImportError:
|
||||
pass
|
||||
# not affected
|
||||
else:
|
||||
if isinstance(asyncio.get_event_loop_policy(), WindowsProactorEventLoopPolicy):
|
||||
# WindowsProactorEventLoopPolicy is not compatible with tornado 6
|
||||
# fallback to the pre-3.8 default of Selector
|
||||
asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())
|
||||
|
||||
def initialize(self, bot, update_queue, default_quote=None):
|
||||
self.bot = bot
|
||||
|
||||
Vendored
+1
-1
Submodule telegram/vendor/ptb_urllib3 updated: d2403a79fc...1954df0395
+1
-1
@@ -17,4 +17,4 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
__version__ = '12.4.2'
|
||||
__version__ = '12.5'
|
||||
|
||||
@@ -34,11 +34,6 @@ from telegram.ext import Dispatcher, JobQueue, Updater, BaseFilter, Defaults
|
||||
from telegram.utils.helpers import _UtcOffsetTimezone
|
||||
from tests.bots import get_bot
|
||||
|
||||
TRAVIS = os.getenv('TRAVIS', False)
|
||||
|
||||
if TRAVIS:
|
||||
pytest_plugins = ['tests.travis_fold']
|
||||
|
||||
GITHUB_ACTION = os.getenv('GITHUB_ACTION', False)
|
||||
|
||||
if GITHUB_ACTION:
|
||||
|
||||
+19
-6
@@ -41,6 +41,7 @@ def animation(bot, chat_id):
|
||||
|
||||
class TestAnimation(object):
|
||||
animation_file_id = 'CgADAQADngIAAuyVeEez0xRovKi9VAI'
|
||||
animation_file_unique_id = 'adc3145fd2e84d95b64d68eaa22aa33e'
|
||||
width = 320
|
||||
height = 180
|
||||
duration = 1
|
||||
@@ -55,7 +56,9 @@ class TestAnimation(object):
|
||||
def test_creation(self, animation):
|
||||
assert isinstance(animation, Animation)
|
||||
assert isinstance(animation.file_id, str)
|
||||
assert isinstance(animation.file_unique_id, str)
|
||||
assert animation.file_id != ''
|
||||
assert animation.file_unique_id != ''
|
||||
|
||||
def test_expected_values(self, animation):
|
||||
assert animation.file_size == self.file_size
|
||||
@@ -73,7 +76,9 @@ class TestAnimation(object):
|
||||
|
||||
assert isinstance(message.animation, Animation)
|
||||
assert isinstance(message.animation.file_id, str)
|
||||
assert isinstance(message.animation.file_unique_id, str)
|
||||
assert message.animation.file_id != ''
|
||||
assert message.animation.file_unique_id != ''
|
||||
assert message.animation.file_name == animation.file_name
|
||||
assert message.animation.mime_type == animation.mime_type
|
||||
assert message.animation.file_size == animation.file_size
|
||||
@@ -103,8 +108,12 @@ class TestAnimation(object):
|
||||
|
||||
assert isinstance(message.animation, Animation)
|
||||
assert isinstance(message.animation.file_id, str)
|
||||
assert message.animation.file_id is not None
|
||||
assert isinstance(message.animation.file_unique_id, str)
|
||||
assert message.animation.file_id != ''
|
||||
assert message.animation.file_unique_id != ''
|
||||
|
||||
assert message.animation.duration == animation.duration
|
||||
assert message.animation.file_name == animation.file_name
|
||||
assert message.animation.mime_type == animation.mime_type
|
||||
assert message.animation.file_size == animation.file_size
|
||||
|
||||
@@ -143,7 +152,6 @@ class TestAnimation(object):
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
@pytest.mark.skip(reason='Doesnt work without API 4.5')
|
||||
def test_resend(self, bot, chat_id, animation):
|
||||
message = bot.send_animation(chat_id, animation.file_id)
|
||||
|
||||
@@ -160,6 +168,7 @@ class TestAnimation(object):
|
||||
def test_de_json(self, bot, animation):
|
||||
json_dict = {
|
||||
'file_id': self.animation_file_id,
|
||||
'file_unique_id': self.animation_file_unique_id,
|
||||
'width': self.width,
|
||||
'height': self.height,
|
||||
'duration': self.duration,
|
||||
@@ -170,6 +179,7 @@ class TestAnimation(object):
|
||||
}
|
||||
animation = Animation.de_json(json_dict, bot)
|
||||
assert animation.file_id == self.animation_file_id
|
||||
assert animation.file_unique_id == self.animation_file_unique_id
|
||||
assert animation.thumb == animation.thumb
|
||||
assert animation.file_name == self.file_name
|
||||
assert animation.mime_type == self.mime_type
|
||||
@@ -180,6 +190,7 @@ class TestAnimation(object):
|
||||
|
||||
assert isinstance(animation_dict, dict)
|
||||
assert animation_dict['file_id'] == animation.file_id
|
||||
assert animation_dict['file_unique_id'] == animation.file_unique_id
|
||||
assert animation_dict['width'] == animation.width
|
||||
assert animation_dict['height'] == animation.height
|
||||
assert animation_dict['duration'] == animation.duration
|
||||
@@ -214,10 +225,12 @@ class TestAnimation(object):
|
||||
assert animation.get_file()
|
||||
|
||||
def test_equality(self):
|
||||
a = Animation(self.animation_file_id, self.height, self.width, self.duration)
|
||||
b = Animation(self.animation_file_id, self.height, self.width, self.duration)
|
||||
d = Animation('', 0, 0, 0)
|
||||
e = Voice(self.animation_file_id, 0)
|
||||
a = Animation(self.animation_file_id, self.animation_file_unique_id,
|
||||
self.height, self.width, self.duration)
|
||||
b = Animation('', self.animation_file_unique_id,
|
||||
self.height, self.width, self.duration)
|
||||
d = Animation('', '', 0, 0, 0)
|
||||
e = Voice(self.animation_file_id, self.animation_file_unique_id, 0)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
+28
-15
@@ -52,12 +52,16 @@ class TestAudio(object):
|
||||
thumb_file_size = 1427
|
||||
thumb_width = 50
|
||||
thumb_height = 50
|
||||
audio_file_id = '5a3128a4d2a04750b5b58397f3b5e812'
|
||||
audio_file_unique_id = 'adc3145fd2e84d95b64d68eaa22aa33e'
|
||||
|
||||
def test_creation(self, audio):
|
||||
# Make sure file has been uploaded.
|
||||
assert isinstance(audio, Audio)
|
||||
assert isinstance(audio.file_id, str)
|
||||
assert isinstance(audio.file_unique_id, str)
|
||||
assert audio.file_id != ''
|
||||
assert audio.file_unique_id != ''
|
||||
|
||||
def test_expected_values(self, audio):
|
||||
assert audio.duration == self.duration
|
||||
@@ -81,6 +85,8 @@ class TestAudio(object):
|
||||
|
||||
assert isinstance(message.audio, Audio)
|
||||
assert isinstance(message.audio.file_id, str)
|
||||
assert isinstance(message.audio.file_unique_id, str)
|
||||
assert message.audio.file_unique_id is not None
|
||||
assert message.audio.file_id is not None
|
||||
assert message.audio.duration == self.duration
|
||||
assert message.audio.performer == self.performer
|
||||
@@ -98,6 +104,7 @@ class TestAudio(object):
|
||||
|
||||
assert new_file.file_size == self.file_size
|
||||
assert new_file.file_id == audio.file_id
|
||||
assert new_file.file_unique_id == audio.file_unique_id
|
||||
assert new_file.file_path.startswith('https://')
|
||||
|
||||
new_file.download('telegram.mp3')
|
||||
@@ -113,6 +120,8 @@ class TestAudio(object):
|
||||
|
||||
assert isinstance(message.audio, Audio)
|
||||
assert isinstance(message.audio.file_id, str)
|
||||
assert isinstance(message.audio.file_unique_id, str)
|
||||
assert message.audio.file_unique_id is not None
|
||||
assert message.audio.file_id is not None
|
||||
assert message.audio.duration == audio.duration
|
||||
assert message.audio.mime_type == audio.mime_type
|
||||
@@ -120,7 +129,6 @@ class TestAudio(object):
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
@pytest.mark.skip(reason='Doesnt work without API 4.5')
|
||||
def test_resend(self, bot, chat_id, audio):
|
||||
message = bot.send_audio(chat_id=chat_id, audio=audio.file_id)
|
||||
|
||||
@@ -168,17 +176,21 @@ class TestAudio(object):
|
||||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
def test_de_json(self, bot, audio):
|
||||
json_dict = {'file_id': 'not a file id',
|
||||
'duration': self.duration,
|
||||
'performer': self.performer,
|
||||
'title': self.title,
|
||||
'caption': self.caption,
|
||||
'mime_type': self.mime_type,
|
||||
'file_size': self.file_size,
|
||||
'thumb': audio.thumb.to_dict()}
|
||||
json_dict = {
|
||||
'file_id': self.audio_file_id,
|
||||
'file_unique_id': self.audio_file_unique_id,
|
||||
'duration': self.duration,
|
||||
'performer': self.performer,
|
||||
'title': self.title,
|
||||
'caption': self.caption,
|
||||
'mime_type': self.mime_type,
|
||||
'file_size': self.file_size,
|
||||
'thumb': audio.thumb.to_dict()
|
||||
}
|
||||
json_audio = Audio.de_json(json_dict, bot)
|
||||
|
||||
assert json_audio.file_id == 'not a file id'
|
||||
assert json_audio.file_id == self.audio_file_id
|
||||
assert json_audio.file_unique_id == self.audio_file_unique_id
|
||||
assert json_audio.duration == self.duration
|
||||
assert json_audio.performer == self.performer
|
||||
assert json_audio.title == self.title
|
||||
@@ -191,6 +203,7 @@ class TestAudio(object):
|
||||
|
||||
assert isinstance(audio_dict, dict)
|
||||
assert audio_dict['file_id'] == audio.file_id
|
||||
assert audio_dict['file_unique_id'] == audio.file_unique_id
|
||||
assert audio_dict['duration'] == audio.duration
|
||||
assert audio_dict['mime_type'] == audio.mime_type
|
||||
assert audio_dict['file_size'] == audio.file_size
|
||||
@@ -221,11 +234,11 @@ class TestAudio(object):
|
||||
assert audio.get_file()
|
||||
|
||||
def test_equality(self, audio):
|
||||
a = Audio(audio.file_id, audio.duration)
|
||||
b = Audio(audio.file_id, audio.duration)
|
||||
c = Audio(audio.file_id, 0)
|
||||
d = Audio('', audio.duration)
|
||||
e = Voice(audio.file_id, audio.duration)
|
||||
a = Audio(audio.file_id, audio.file_unique_id, audio.duration)
|
||||
b = Audio('', audio.file_unique_id, audio.duration)
|
||||
c = Audio(audio.file_id, audio.file_unique_id, 0)
|
||||
d = Audio('', '', audio.duration)
|
||||
e = Voice(audio.file_id, audio.file_unique_id, audio.duration)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
+25
-5
@@ -16,8 +16,6 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import datetime as dtm
|
||||
from platform import python_implementation
|
||||
@@ -89,6 +87,10 @@ class TestBot(object):
|
||||
assert get_me_bot.first_name == bot.first_name
|
||||
assert get_me_bot.last_name == bot.last_name
|
||||
assert get_me_bot.name == bot.name
|
||||
assert get_me_bot.can_join_groups == bot.can_join_groups
|
||||
assert get_me_bot.can_read_all_group_messages == bot.can_read_all_group_messages
|
||||
assert get_me_bot.supports_inline_queries == bot.supports_inline_queries
|
||||
assert 'https://t.me/{}'.format(get_me_bot.username) == bot.link
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
@@ -176,14 +178,17 @@ class TestBot(object):
|
||||
question = 'Is this a test?'
|
||||
answers = ['Yes', 'No', 'Maybe']
|
||||
message = bot.send_poll(chat_id=super_group_id, question=question, options=answers,
|
||||
timeout=60)
|
||||
is_anonymous=False, allows_multiple_answers=True, timeout=60)
|
||||
|
||||
assert message.poll
|
||||
assert message.poll.question == question
|
||||
assert message.poll.options[0].text == answers[0]
|
||||
assert message.poll.options[1].text == answers[1]
|
||||
assert message.poll.options[2].text == answers[2]
|
||||
assert not message.poll.is_anonymous
|
||||
assert message.poll.allows_multiple_answers
|
||||
assert not message.poll.is_closed
|
||||
assert message.poll.type == Poll.REGULAR
|
||||
|
||||
poll = bot.stop_poll(chat_id=super_group_id, message_id=message.message_id, timeout=60)
|
||||
assert isinstance(poll, Poll)
|
||||
@@ -195,6 +200,13 @@ class TestBot(object):
|
||||
assert poll.options[2].text == answers[2]
|
||||
assert poll.options[2].voter_count == 0
|
||||
assert poll.question == question
|
||||
assert poll.total_voter_count == 0
|
||||
|
||||
message_quiz = bot.send_poll(chat_id=super_group_id, question=question, options=answers,
|
||||
type=Poll.QUIZ, correct_option_id=2, is_closed=True)
|
||||
assert message_quiz.poll.correct_option_id == 2
|
||||
assert message_quiz.poll.type == Poll.QUIZ
|
||||
assert message_quiz.poll.is_closed
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
@@ -350,6 +362,16 @@ class TestBot(object):
|
||||
|
||||
assert bot.set_chat_permissions(2, chat_permissions)
|
||||
|
||||
def test_set_chat_administrator_custom_title(self, monkeypatch, bot):
|
||||
def test(_, url, data, *args, **kwargs):
|
||||
chat_id = data['chat_id'] == 2
|
||||
user_id = data['user_id'] == 32
|
||||
custom_title = data['custom_title'] == 'custom_title'
|
||||
return chat_id and user_id and custom_title
|
||||
|
||||
monkeypatch.setattr('telegram.utils.request.Request.post', test)
|
||||
assert bot.set_chat_administrator_custom_title(2, 32, 'custom_title')
|
||||
|
||||
# TODO: Needs improvement. Need an incoming callbackquery to test
|
||||
def test_answer_callback_query(self, monkeypatch, bot):
|
||||
# For now just test that our internals pass the correct data
|
||||
@@ -493,8 +515,6 @@ class TestBot(object):
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(15)
|
||||
@pytest.mark.xfail
|
||||
@pytest.mark.skipif(os.getenv('APPVEYOR') and (sys.version_info < (3, 6)),
|
||||
reason='only run on 3.6 on appveyor')
|
||||
def test_set_webhook_get_webhook_info_and_delete_webhook(self, bot):
|
||||
url = 'https://python-telegram-bot.org/test/webhook'
|
||||
max_connections = 7
|
||||
|
||||
+18
-18
@@ -24,7 +24,7 @@ from telegram import CallbackQuery, User, Message, Chat, Audio
|
||||
|
||||
@pytest.fixture(scope='class', params=['message', 'inline'])
|
||||
def callback_query(bot, request):
|
||||
cbq = CallbackQuery(TestCallbackQuery.id,
|
||||
cbq = CallbackQuery(TestCallbackQuery.id_,
|
||||
TestCallbackQuery.from_user,
|
||||
TestCallbackQuery.chat_instance,
|
||||
data=TestCallbackQuery.data,
|
||||
@@ -38,7 +38,7 @@ def callback_query(bot, request):
|
||||
|
||||
|
||||
class TestCallbackQuery(object):
|
||||
id = 'id'
|
||||
id_ = 'id'
|
||||
from_user = User(1, 'test_user', False)
|
||||
chat_instance = 'chat_instance'
|
||||
message = Message(3, User(5, 'bot', False), None, Chat(4, 'private'))
|
||||
@@ -47,7 +47,7 @@ class TestCallbackQuery(object):
|
||||
game_short_name = 'the_game'
|
||||
|
||||
def test_de_json(self, bot):
|
||||
json_dict = {'id': self.id,
|
||||
json_dict = {'id': self.id_,
|
||||
'from': self.from_user.to_dict(),
|
||||
'chat_instance': self.chat_instance,
|
||||
'message': self.message.to_dict(),
|
||||
@@ -57,7 +57,7 @@ class TestCallbackQuery(object):
|
||||
'default_quote': True}
|
||||
callback_query = CallbackQuery.de_json(json_dict, bot)
|
||||
|
||||
assert callback_query.id == self.id
|
||||
assert callback_query.id == self.id_
|
||||
assert callback_query.from_user == self.from_user
|
||||
assert callback_query.chat_instance == self.chat_instance
|
||||
assert callback_query.message == self.message
|
||||
@@ -92,8 +92,8 @@ class TestCallbackQuery(object):
|
||||
def test(*args, **kwargs):
|
||||
text = args[0] == 'test'
|
||||
try:
|
||||
id = kwargs['inline_message_id'] == callback_query.inline_message_id
|
||||
return id and text
|
||||
id_ = kwargs['inline_message_id'] == callback_query.inline_message_id
|
||||
return id_ and text
|
||||
except KeyError:
|
||||
chat_id = kwargs['chat_id'] == callback_query.message.chat_id
|
||||
message_id = kwargs['message_id'] == callback_query.message.message_id
|
||||
@@ -107,12 +107,12 @@ class TestCallbackQuery(object):
|
||||
def test(*args, **kwargs):
|
||||
caption = kwargs['caption'] == 'new caption'
|
||||
try:
|
||||
id = kwargs['inline_message_id'] == callback_query.inline_message_id
|
||||
return id and caption
|
||||
id_ = kwargs['inline_message_id'] == callback_query.inline_message_id
|
||||
return id_ and caption
|
||||
except KeyError:
|
||||
id = kwargs['chat_id'] == callback_query.message.chat_id
|
||||
id_ = kwargs['chat_id'] == callback_query.message.chat_id
|
||||
message = kwargs['message_id'] == callback_query.message.message_id
|
||||
return id and message and caption
|
||||
return id_ and message and caption
|
||||
|
||||
monkeypatch.setattr(callback_query.bot, 'edit_message_caption', test)
|
||||
assert callback_query.edit_message_caption(caption='new caption')
|
||||
@@ -122,23 +122,23 @@ class TestCallbackQuery(object):
|
||||
def test(*args, **kwargs):
|
||||
reply_markup = kwargs['reply_markup'] == [['1', '2']]
|
||||
try:
|
||||
id = kwargs['inline_message_id'] == callback_query.inline_message_id
|
||||
return id and reply_markup
|
||||
id_ = kwargs['inline_message_id'] == callback_query.inline_message_id
|
||||
return id_ and reply_markup
|
||||
except KeyError:
|
||||
id = kwargs['chat_id'] == callback_query.message.chat_id
|
||||
id_ = kwargs['chat_id'] == callback_query.message.chat_id
|
||||
message = kwargs['message_id'] == callback_query.message.message_id
|
||||
return id and message and reply_markup
|
||||
return id_ and message and reply_markup
|
||||
|
||||
monkeypatch.setattr(callback_query.bot, 'edit_message_reply_markup', test)
|
||||
assert callback_query.edit_message_reply_markup(reply_markup=[['1', '2']])
|
||||
assert callback_query.edit_message_reply_markup([['1', '2']])
|
||||
|
||||
def test_equality(self):
|
||||
a = CallbackQuery(self.id, self.from_user, 'chat')
|
||||
b = CallbackQuery(self.id, self.from_user, 'chat')
|
||||
c = CallbackQuery(self.id, None, '')
|
||||
a = CallbackQuery(self.id_, self.from_user, 'chat')
|
||||
b = CallbackQuery(self.id_, self.from_user, 'chat')
|
||||
c = CallbackQuery(self.id_, None, '')
|
||||
d = CallbackQuery('', None, 'chat')
|
||||
e = Audio(self.id, 1)
|
||||
e = Audio(self.id_, 'unique_id', 1)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
+33
-18
@@ -25,17 +25,18 @@ from telegram import User, Message
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def chat(bot):
|
||||
return Chat(TestChat.id, TestChat.title, TestChat.type, username=TestChat.username,
|
||||
return Chat(TestChat.id_, TestChat.title, TestChat.type_, username=TestChat.username,
|
||||
all_members_are_administrators=TestChat.all_members_are_administrators,
|
||||
bot=bot, sticker_set_name=TestChat.sticker_set_name,
|
||||
can_set_sticker_set=TestChat.can_set_sticker_set,
|
||||
permissions=TestChat.permissions)
|
||||
permissions=TestChat.permissions,
|
||||
slow_mode_delay=TestChat.slow_mode_delay)
|
||||
|
||||
|
||||
class TestChat(object):
|
||||
id = -28767330
|
||||
id_ = -28767330
|
||||
title = 'ToledosPalaceBot - Group'
|
||||
type = 'group'
|
||||
type_ = 'group'
|
||||
username = 'username'
|
||||
all_members_are_administrators = False
|
||||
sticker_set_name = 'stickers'
|
||||
@@ -45,33 +46,36 @@ class TestChat(object):
|
||||
can_change_info=False,
|
||||
can_invite_users=True,
|
||||
)
|
||||
slow_mode_delay = 30
|
||||
|
||||
def test_de_json(self, bot):
|
||||
json_dict = {
|
||||
'id': self.id,
|
||||
'id': self.id_,
|
||||
'title': self.title,
|
||||
'type': self.type,
|
||||
'type': self.type_,
|
||||
'username': self.username,
|
||||
'all_members_are_administrators': self.all_members_are_administrators,
|
||||
'sticker_set_name': self.sticker_set_name,
|
||||
'can_set_sticker_set': self.can_set_sticker_set,
|
||||
'permissions': self.permissions.to_dict()
|
||||
'permissions': self.permissions.to_dict(),
|
||||
'slow_mode_delay': self.slow_mode_delay
|
||||
}
|
||||
chat = Chat.de_json(json_dict, bot)
|
||||
|
||||
assert chat.id == self.id
|
||||
assert chat.id == self.id_
|
||||
assert chat.title == self.title
|
||||
assert chat.type == self.type
|
||||
assert chat.type == self.type_
|
||||
assert chat.username == self.username
|
||||
assert chat.all_members_are_administrators == self.all_members_are_administrators
|
||||
assert chat.sticker_set_name == self.sticker_set_name
|
||||
assert chat.can_set_sticker_set == self.can_set_sticker_set
|
||||
assert chat.permissions == self.permissions
|
||||
assert chat.slow_mode_delay == self.slow_mode_delay
|
||||
|
||||
def test_de_json_default_quote(self, bot):
|
||||
json_dict = {
|
||||
'id': self.id,
|
||||
'type': self.type,
|
||||
'id': self.id_,
|
||||
'type': self.type_,
|
||||
'pinned_message': Message(
|
||||
message_id=123,
|
||||
from_user=None,
|
||||
@@ -94,6 +98,7 @@ class TestChat(object):
|
||||
assert chat_dict['username'] == chat.username
|
||||
assert chat_dict['all_members_are_administrators'] == chat.all_members_are_administrators
|
||||
assert chat_dict['permissions'] == chat.permissions.to_dict()
|
||||
assert chat_dict['slow_mode_delay'] == chat.slow_mode_delay
|
||||
|
||||
def test_link(self, chat):
|
||||
assert chat.link == 'https://t.me/{}'.format(chat.username)
|
||||
@@ -102,9 +107,9 @@ class TestChat(object):
|
||||
|
||||
def test_send_action(self, monkeypatch, chat):
|
||||
def test(*args, **kwargs):
|
||||
id = args[0] == chat.id
|
||||
id_ = args[0] == chat.id
|
||||
action = kwargs['action'] == ChatAction.TYPING
|
||||
return id and action
|
||||
return id_ and action
|
||||
|
||||
monkeypatch.setattr(chat.bot, 'send_chat_action', test)
|
||||
assert chat.send_action(action=ChatAction.TYPING)
|
||||
@@ -167,6 +172,16 @@ class TestChat(object):
|
||||
monkeypatch.setattr(chat.bot, 'set_chat_permissions', test)
|
||||
assert chat.set_permissions(self.permissions)
|
||||
|
||||
def test_set_administrator_custom_title(self, monkeypatch, chat):
|
||||
def test(*args, **kwargs):
|
||||
chat_id = args[1] == chat.id
|
||||
user_id = args[2] == 42
|
||||
custom_title = args[3] == 'custom_title'
|
||||
return chat_id and user_id and custom_title
|
||||
|
||||
monkeypatch.setattr('telegram.Bot.set_chat_administrator_custom_title', test)
|
||||
assert chat.set_administrator_custom_title(42, 'custom_title')
|
||||
|
||||
def test_instance_method_send_message(self, monkeypatch, chat):
|
||||
def test(*args, **kwargs):
|
||||
return args[0] == chat.id and args[1] == 'test'
|
||||
@@ -238,11 +253,11 @@ class TestChat(object):
|
||||
assert chat.send_poll('test_poll')
|
||||
|
||||
def test_equality(self):
|
||||
a = Chat(self.id, self.title, self.type)
|
||||
b = Chat(self.id, self.title, self.type)
|
||||
c = Chat(self.id, '', '')
|
||||
d = Chat(0, self.title, self.type)
|
||||
e = User(self.id, '', False)
|
||||
a = Chat(self.id_, self.title, self.type_)
|
||||
b = Chat(self.id_, self.title, self.type_)
|
||||
c = Chat(self.id_, '', '')
|
||||
d = Chat(0, self.title, self.type_)
|
||||
e = User(self.id_, '', False)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -47,8 +47,11 @@ class TestChatMember(object):
|
||||
|
||||
def test_de_json_all_args(self, bot, user):
|
||||
time = datetime.datetime.utcnow()
|
||||
custom_title = 'custom_title'
|
||||
|
||||
json_dict = {'user': user.to_dict(),
|
||||
'status': self.status,
|
||||
'custom_title': custom_title,
|
||||
'until_date': to_timestamp(time),
|
||||
'can_be_edited': False,
|
||||
'can_change_info': True,
|
||||
@@ -69,6 +72,7 @@ class TestChatMember(object):
|
||||
|
||||
assert chat_member.user == user
|
||||
assert chat_member.status == self.status
|
||||
assert chat_member.custom_title == custom_title
|
||||
assert chat_member.can_be_edited is False
|
||||
assert chat_member.can_change_info is True
|
||||
assert chat_member.can_post_messages is False
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# 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/].
|
||||
|
||||
import os
|
||||
import pytest
|
||||
from flaky import flaky
|
||||
|
||||
from telegram import ChatPhoto, Voice, TelegramError
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def chatphoto_file():
|
||||
f = open('tests/data/telegram.jpg', 'rb')
|
||||
yield f
|
||||
f.close()
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def chat_photo(bot, super_group_id):
|
||||
return bot.get_chat(super_group_id, timeout=50).photo
|
||||
|
||||
|
||||
class TestChatPhoto(object):
|
||||
chatphoto_small_file_id = 'smallCgADAQADngIAAuyVeEez0xRovKi9VAI'
|
||||
chatphoto_big_file_id = 'bigCgADAQADngIAAuyVeEez0xRovKi9VAI'
|
||||
chatphoto_small_file_unique_id = 'smalladc3145fd2e84d95b64d68eaa22aa33e'
|
||||
chatphoto_big_file_unique_id = 'bigadc3145fd2e84d95b64d68eaa22aa33e'
|
||||
chatphoto_file_url = 'https://python-telegram-bot.org/static/testfiles/telegram.jpg'
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
def test_send_all_args(self, bot, super_group_id, chatphoto_file, chat_photo, thumb_file):
|
||||
assert bot.set_chat_photo(super_group_id, chatphoto_file)
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
def test_get_and_download(self, bot, chat_photo):
|
||||
new_file = bot.get_file(chat_photo.small_file_id)
|
||||
|
||||
assert new_file.file_id == chat_photo.small_file_id
|
||||
assert new_file.file_path.startswith('https://')
|
||||
|
||||
new_file.download('telegram.jpg')
|
||||
|
||||
assert os.path.isfile('telegram.jpg')
|
||||
|
||||
new_file = bot.get_file(chat_photo.big_file_id)
|
||||
|
||||
assert new_file.file_id == chat_photo.big_file_id
|
||||
assert new_file.file_path.startswith('https://')
|
||||
|
||||
new_file.download('telegram.jpg')
|
||||
|
||||
assert os.path.isfile('telegram.jpg')
|
||||
|
||||
def test_send_with_chat_photo(self, monkeypatch, bot, super_group_id, chat_photo):
|
||||
def test(_, url, data, **kwargs):
|
||||
return data['photo'] == chat_photo
|
||||
|
||||
monkeypatch.setattr('telegram.utils.request.Request.post', test)
|
||||
message = bot.set_chat_photo(photo=chat_photo, chat_id=super_group_id)
|
||||
assert message
|
||||
|
||||
def test_de_json(self, bot, chat_photo):
|
||||
json_dict = {
|
||||
'small_file_id': self.chatphoto_small_file_id,
|
||||
'big_file_id': self.chatphoto_big_file_id,
|
||||
'small_file_unique_id': self.chatphoto_small_file_unique_id,
|
||||
'big_file_unique_id': self.chatphoto_big_file_unique_id,
|
||||
}
|
||||
chat_photo = ChatPhoto.de_json(json_dict, bot)
|
||||
assert chat_photo.small_file_id == self.chatphoto_small_file_id
|
||||
assert chat_photo.big_file_id == self.chatphoto_big_file_id
|
||||
assert chat_photo.small_file_unique_id == self.chatphoto_small_file_unique_id
|
||||
assert chat_photo.big_file_unique_id == self.chatphoto_big_file_unique_id
|
||||
|
||||
def test_to_dict(self, chat_photo):
|
||||
chat_photo_dict = chat_photo.to_dict()
|
||||
|
||||
assert isinstance(chat_photo_dict, dict)
|
||||
assert chat_photo_dict['small_file_id'] == chat_photo.small_file_id
|
||||
assert chat_photo_dict['big_file_id'] == chat_photo.big_file_id
|
||||
assert chat_photo_dict['small_file_unique_id'] == chat_photo.small_file_unique_id
|
||||
assert chat_photo_dict['big_file_unique_id'] == chat_photo.big_file_unique_id
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
def test_error_send_empty_file(self, bot, super_group_id):
|
||||
chatphoto_file = open(os.devnull, 'rb')
|
||||
|
||||
with pytest.raises(TelegramError):
|
||||
bot.set_chat_photo(chat_id=super_group_id, photo=chatphoto_file)
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
def test_error_send_empty_file_id(self, bot, super_group_id):
|
||||
with pytest.raises(TelegramError):
|
||||
bot.set_chat_photo(chat_id=super_group_id, photo='')
|
||||
|
||||
def test_error_send_without_required_args(self, bot, super_group_id):
|
||||
with pytest.raises(TypeError):
|
||||
bot.set_chat_photo(chat_id=super_group_id)
|
||||
|
||||
def test_get_small_file_instance_method(self, monkeypatch, chat_photo):
|
||||
def test(*args, **kwargs):
|
||||
return args[1] == chat_photo.small_file_id
|
||||
|
||||
monkeypatch.setattr('telegram.Bot.get_file', test)
|
||||
assert chat_photo.get_small_file()
|
||||
|
||||
def test_get_big_file_instance_method(self, monkeypatch, chat_photo):
|
||||
def test(*args, **kwargs):
|
||||
return args[1] == chat_photo.big_file_id
|
||||
|
||||
monkeypatch.setattr('telegram.Bot.get_file', test)
|
||||
assert chat_photo.get_big_file()
|
||||
|
||||
def test_equality(self):
|
||||
a = ChatPhoto(self.chatphoto_small_file_id, self.chatphoto_big_file_id,
|
||||
self.chatphoto_small_file_unique_id, self.chatphoto_big_file_unique_id)
|
||||
b = ChatPhoto(self.chatphoto_small_file_id, self.chatphoto_big_file_id,
|
||||
self.chatphoto_small_file_unique_id, self.chatphoto_big_file_unique_id)
|
||||
c = ChatPhoto('', '', self.chatphoto_small_file_unique_id,
|
||||
self.chatphoto_big_file_unique_id)
|
||||
d = ChatPhoto('', '', 0, 0)
|
||||
e = Voice(self.chatphoto_small_file_id, self.chatphoto_small_file_unique_id, 0)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
@@ -74,7 +74,7 @@ class TestChosenInlineResult(object):
|
||||
b = ChosenInlineResult(self.result_id, user, 'Query', '')
|
||||
c = ChosenInlineResult(self.result_id, user, '', '')
|
||||
d = ChosenInlineResult('', user, 'Query', '')
|
||||
e = Voice(self.result_id, 0)
|
||||
e = Voice(self.result_id, 'unique_id', 0)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -80,7 +80,7 @@ class TestContact(object):
|
||||
b = Contact(self.phone_number, self.first_name)
|
||||
c = Contact(self.phone_number, '')
|
||||
d = Contact('', self.first_name)
|
||||
e = Voice('', 0)
|
||||
e = Voice('', 'unique_id', 0)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
+24
-12
@@ -47,11 +47,15 @@ class TestDocument(object):
|
||||
thumb_file_size = 8090
|
||||
thumb_width = 300
|
||||
thumb_height = 300
|
||||
document_file_id = '5a3128a4d2a04750b5b58397f3b5e812'
|
||||
document_file_unique_id = 'adc3145fd2e84d95b64d68eaa22aa33e'
|
||||
|
||||
def test_creation(self, document):
|
||||
assert isinstance(document, Document)
|
||||
assert isinstance(document.file_id, str)
|
||||
assert isinstance(document.file_unique_id, str)
|
||||
assert document.file_id != ''
|
||||
assert document.file_unique_id != ''
|
||||
|
||||
def test_expected_values(self, document):
|
||||
assert document.file_size == self.file_size
|
||||
@@ -71,6 +75,8 @@ class TestDocument(object):
|
||||
assert isinstance(message.document, Document)
|
||||
assert isinstance(message.document.file_id, str)
|
||||
assert message.document.file_id != ''
|
||||
assert isinstance(message.document.file_unique_id, str)
|
||||
assert message.document.file_unique_id != ''
|
||||
assert isinstance(message.document.thumb, PhotoSize)
|
||||
assert message.document.file_name == 'telegram_custom.png'
|
||||
assert message.document.mime_type == document.mime_type
|
||||
@@ -86,6 +92,7 @@ class TestDocument(object):
|
||||
|
||||
assert new_file.file_size == document.file_size
|
||||
assert new_file.file_id == document.file_id
|
||||
assert new_file.file_unique_id == document.file_unique_id
|
||||
assert new_file.file_path.startswith('https://')
|
||||
|
||||
new_file.download('telegram.png')
|
||||
@@ -102,6 +109,8 @@ class TestDocument(object):
|
||||
assert isinstance(document, Document)
|
||||
assert isinstance(document.file_id, str)
|
||||
assert document.file_id != ''
|
||||
assert isinstance(message.document.file_unique_id, str)
|
||||
assert message.document.file_unique_id != ''
|
||||
assert isinstance(document.thumb, PhotoSize)
|
||||
assert document.file_name == 'telegram.gif'
|
||||
assert document.mime_type == 'image/gif'
|
||||
@@ -109,7 +118,6 @@ class TestDocument(object):
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
@pytest.mark.skip(reason='Doesnt work without API 4.5')
|
||||
def test_send_resend(self, bot, chat_id, document):
|
||||
message = bot.send_document(chat_id=chat_id, document=document.file_id)
|
||||
|
||||
@@ -159,15 +167,18 @@ class TestDocument(object):
|
||||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
def test_de_json(self, bot, document):
|
||||
json_dict = {'file_id': 'not a file id',
|
||||
'thumb': document.thumb.to_dict(),
|
||||
'file_name': self.file_name,
|
||||
'mime_type': self.mime_type,
|
||||
'file_size': self.file_size
|
||||
}
|
||||
json_dict = {
|
||||
'file_id': self.document_file_id,
|
||||
'file_unique_id': self.document_file_unique_id,
|
||||
'thumb': document.thumb.to_dict(),
|
||||
'file_name': self.file_name,
|
||||
'mime_type': self.mime_type,
|
||||
'file_size': self.file_size
|
||||
}
|
||||
test_document = Document.de_json(json_dict, bot)
|
||||
|
||||
assert test_document.file_id == 'not a file id'
|
||||
assert test_document.file_id == self.document_file_id
|
||||
assert test_document.file_unique_id == self.document_file_unique_id
|
||||
assert test_document.thumb == document.thumb
|
||||
assert test_document.file_name == self.file_name
|
||||
assert test_document.mime_type == self.mime_type
|
||||
@@ -178,6 +189,7 @@ class TestDocument(object):
|
||||
|
||||
assert isinstance(document_dict, dict)
|
||||
assert document_dict['file_id'] == document.file_id
|
||||
assert document_dict['file_unique_id'] == document.file_unique_id
|
||||
assert document_dict['file_name'] == document.file_name
|
||||
assert document_dict['mime_type'] == document.mime_type
|
||||
assert document_dict['file_size'] == document.file_size
|
||||
@@ -207,10 +219,10 @@ class TestDocument(object):
|
||||
assert document.get_file()
|
||||
|
||||
def test_equality(self, document):
|
||||
a = Document(document.file_id)
|
||||
b = Document(document.file_id)
|
||||
d = Document('')
|
||||
e = Voice(document.file_id, 0)
|
||||
a = Document(document.file_id, document.file_unique_id)
|
||||
b = Document('', document.file_unique_id)
|
||||
d = Document('', '')
|
||||
e = Voice(document.file_id, document.file_unique_id, 0)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -24,7 +24,7 @@ from telegram import EncryptedPassportElement, PassportFile, PassportElementErro
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def encrypted_passport_element():
|
||||
return EncryptedPassportElement(TestEncryptedPassportElement.type,
|
||||
return EncryptedPassportElement(TestEncryptedPassportElement.type_,
|
||||
data=TestEncryptedPassportElement.data,
|
||||
phone_number=TestEncryptedPassportElement.phone_number,
|
||||
email=TestEncryptedPassportElement.email,
|
||||
@@ -35,7 +35,7 @@ def encrypted_passport_element():
|
||||
|
||||
|
||||
class TestEncryptedPassportElement(object):
|
||||
type = 'type'
|
||||
type_ = 'type'
|
||||
data = 'data'
|
||||
phone_number = 'phone_number'
|
||||
email = 'email'
|
||||
@@ -45,7 +45,7 @@ class TestEncryptedPassportElement(object):
|
||||
selfie = PassportFile('file_id', 50, 0)
|
||||
|
||||
def test_expected_values(self, encrypted_passport_element):
|
||||
assert encrypted_passport_element.type == self.type
|
||||
assert encrypted_passport_element.type == self.type_
|
||||
assert encrypted_passport_element.data == self.data
|
||||
assert encrypted_passport_element.phone_number == self.phone_number
|
||||
assert encrypted_passport_element.email == self.email
|
||||
@@ -75,8 +75,8 @@ class TestEncryptedPassportElement(object):
|
||||
== encrypted_passport_element.selfie.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = EncryptedPassportElement(self.type, data=self.data)
|
||||
b = EncryptedPassportElement(self.type, data=self.data)
|
||||
a = EncryptedPassportElement(self.type_, data=self.data)
|
||||
b = EncryptedPassportElement(self.type_, data=self.data)
|
||||
c = EncryptedPassportElement(self.data, '')
|
||||
d = PassportElementError('source', 'type', 'message')
|
||||
|
||||
|
||||
+10
-5
@@ -29,6 +29,7 @@ from telegram import File, TelegramError, Voice
|
||||
@pytest.fixture(scope='class')
|
||||
def file(bot):
|
||||
return File(TestFile.file_id,
|
||||
TestFile.file_unique_id,
|
||||
file_path=TestFile.file_path,
|
||||
file_size=TestFile.file_size,
|
||||
bot=bot)
|
||||
@@ -36,6 +37,7 @@ def file(bot):
|
||||
|
||||
class TestFile(object):
|
||||
file_id = 'NOTVALIDDOESNOTMATTER'
|
||||
file_unique_id = 'adc3145fd2e84d95b64d68eaa22aa33e'
|
||||
file_path = (
|
||||
u'https://api.org/file/bot133505823:AAHZFMHno3mzVLErU5b5jJvaeG--qUyLyG0/document/file_3')
|
||||
file_size = 28232
|
||||
@@ -44,12 +46,14 @@ class TestFile(object):
|
||||
def test_de_json(self, bot):
|
||||
json_dict = {
|
||||
'file_id': self.file_id,
|
||||
'file_unique_id': self.file_unique_id,
|
||||
'file_path': self.file_path,
|
||||
'file_size': self.file_size
|
||||
}
|
||||
new_file = File.de_json(json_dict, bot)
|
||||
|
||||
assert new_file.file_id == self.file_id
|
||||
assert new_file.file_unique_id == self.file_unique_id
|
||||
assert new_file.file_path == self.file_path
|
||||
assert new_file.file_size == self.file_size
|
||||
|
||||
@@ -58,6 +62,7 @@ class TestFile(object):
|
||||
|
||||
assert isinstance(file_dict, dict)
|
||||
assert file_dict['file_id'] == file.file_id
|
||||
assert file_dict['file_unique_id'] == file.file_unique_id
|
||||
assert file_dict['file_path'] == file.file_path
|
||||
assert file_dict['file_size'] == file.file_size
|
||||
|
||||
@@ -142,11 +147,11 @@ class TestFile(object):
|
||||
assert buf2[:len(buf)] == buf
|
||||
|
||||
def test_equality(self, bot):
|
||||
a = File(self.file_id, bot)
|
||||
b = File(self.file_id, bot)
|
||||
c = File(self.file_id, None)
|
||||
d = File('', bot)
|
||||
e = Voice(self.file_id, 0)
|
||||
a = File(self.file_id, self.file_unique_id, bot)
|
||||
b = File('', self.file_unique_id, bot)
|
||||
c = File(self.file_id, self.file_unique_id, None)
|
||||
d = File('', '', bot)
|
||||
e = Voice(self.file_id, self.file_unique_id, 0)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -300,7 +300,7 @@ class TestFilters(object):
|
||||
assert Filters.document(update)
|
||||
|
||||
def test_filters_document_type(self, update):
|
||||
update.message.document = Document("file_id",
|
||||
update.message.document = Document("file_id", 'unique_id',
|
||||
mime_type="application/vnd.android.package-archive")
|
||||
assert Filters.document.apk(update)
|
||||
assert Filters.document.application(update)
|
||||
|
||||
+2
-2
@@ -35,11 +35,11 @@ def game():
|
||||
class TestGame(object):
|
||||
title = 'Python-telegram-bot Test Game'
|
||||
description = 'description'
|
||||
photo = [PhotoSize('Blah', 640, 360, file_size=0)]
|
||||
photo = [PhotoSize('Blah', 'ElseBlah', 640, 360, file_size=0)]
|
||||
text = (b'\\U0001f469\\u200d\\U0001f469\\u200d\\U0001f467'
|
||||
b'\\u200d\\U0001f467\\U0001f431http://google.com').decode('unicode-escape')
|
||||
text_entities = [MessageEntity(13, 17, MessageEntity.URL)]
|
||||
animation = Animation('blah', 320, 180, 1)
|
||||
animation = Animation('blah', 'unique_id', 320, 180, 1)
|
||||
|
||||
def test_de_json_required(self, bot):
|
||||
json_dict = {
|
||||
|
||||
+36
-1
@@ -24,6 +24,7 @@ import pytest
|
||||
from telegram import Sticker
|
||||
from telegram import Update
|
||||
from telegram import User
|
||||
from telegram import MessageEntity
|
||||
from telegram.message import Message
|
||||
from telegram.utils import helpers
|
||||
from telegram.utils.helpers import _UtcOffsetTimezone, _datetime_to_float_timestamp
|
||||
@@ -46,6 +47,34 @@ class TestHelpers(object):
|
||||
|
||||
assert expected_str == helpers.escape_markdown(test_str)
|
||||
|
||||
def test_escape_markdown_v2(self):
|
||||
test_str = 'a_b*c[d]e (fg) h~I`>JK#L+MN -O=|p{qr}s.t! u'
|
||||
expected_str = 'a\_b\*c\[d\]e \(fg\) h\~I\`\>JK\#L\+MN \-O\=\|p\{qr\}s\.t\! u'
|
||||
|
||||
assert expected_str == helpers.escape_markdown(test_str, version=2)
|
||||
|
||||
def test_escape_markdown_v2_monospaced(self):
|
||||
|
||||
test_str = 'mono/pre: `abc` \int (`\some \`stuff)'
|
||||
expected_str = 'mono/pre: \`abc\` \\\\int (\`\\\\some \\\\\`stuff)'
|
||||
|
||||
assert expected_str == helpers.escape_markdown(test_str, version=2,
|
||||
entity_type=MessageEntity.PRE)
|
||||
assert expected_str == helpers.escape_markdown(test_str, version=2,
|
||||
entity_type=MessageEntity.CODE)
|
||||
|
||||
def test_escape_markdown_v2_text_link(self):
|
||||
|
||||
test_str = 'https://url.containing/funny)cha)\\ra\)cter\s'
|
||||
expected_str = 'https://url.containing/funny\)cha\)\\\\ra\\\\\)cter\\\\s'
|
||||
|
||||
assert expected_str == helpers.escape_markdown(test_str, version=2,
|
||||
entity_type=MessageEntity.TEXT_LINK)
|
||||
|
||||
def test_markdown_invalid_version(self):
|
||||
with pytest.raises(ValueError):
|
||||
helpers.escape_markdown('abc', version=-1)
|
||||
|
||||
def test_to_float_timestamp_absolute_naive(self):
|
||||
"""Conversion from timezone-naive datetime to timestamp.
|
||||
Naive datetimes should be assumed to be in UTC.
|
||||
@@ -161,7 +190,8 @@ class TestHelpers(object):
|
||||
assert helpers.effective_message_type(test_message) == 'text'
|
||||
test_message.text = None
|
||||
|
||||
test_message = build_test_message(sticker=Sticker('sticker_id', 50, 50, False))
|
||||
test_message = build_test_message(sticker=Sticker('sticker_id', 'unique_id',
|
||||
50, 50, False))
|
||||
assert helpers.effective_message_type(test_message) == 'sticker'
|
||||
test_message.sticker = None
|
||||
|
||||
@@ -188,3 +218,8 @@ class TestHelpers(object):
|
||||
expected = '[the name](tg://user?id=1)'
|
||||
|
||||
assert expected == helpers.mention_markdown(1, 'the name')
|
||||
|
||||
def test_mention_markdown_2(self):
|
||||
expected = r'[the\_name](tg://user?id=1)'
|
||||
|
||||
assert expected == helpers.mention_markdown(1, 'the_name')
|
||||
|
||||
@@ -24,12 +24,12 @@ from telegram import User, Location, InlineQuery, Update
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query(bot):
|
||||
return InlineQuery(TestInlineQuery.id, TestInlineQuery.from_user, TestInlineQuery.query,
|
||||
return InlineQuery(TestInlineQuery.id_, TestInlineQuery.from_user, TestInlineQuery.query,
|
||||
TestInlineQuery.offset, location=TestInlineQuery.location, bot=bot)
|
||||
|
||||
|
||||
class TestInlineQuery(object):
|
||||
id = 1234
|
||||
id_ = 1234
|
||||
from_user = User(1, 'First name', False)
|
||||
query = 'query text'
|
||||
offset = 'offset'
|
||||
@@ -37,7 +37,7 @@ class TestInlineQuery(object):
|
||||
|
||||
def test_de_json(self, bot):
|
||||
json_dict = {
|
||||
'id': self.id,
|
||||
'id': self.id_,
|
||||
'from': self.from_user.to_dict(),
|
||||
'query': self.query,
|
||||
'offset': self.offset,
|
||||
@@ -45,7 +45,7 @@ class TestInlineQuery(object):
|
||||
}
|
||||
inline_query_json = InlineQuery.de_json(json_dict, bot)
|
||||
|
||||
assert inline_query_json.id == self.id
|
||||
assert inline_query_json.id == self.id_
|
||||
assert inline_query_json.from_user == self.from_user
|
||||
assert inline_query_json.location == self.location
|
||||
assert inline_query_json.query == self.query
|
||||
@@ -69,11 +69,11 @@ class TestInlineQuery(object):
|
||||
assert inline_query.answer()
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQuery(self.id, User(1, '', False), '', '')
|
||||
b = InlineQuery(self.id, User(1, '', False), '', '')
|
||||
c = InlineQuery(self.id, User(0, '', False), '', '')
|
||||
a = InlineQuery(self.id_, User(1, '', False), '', '')
|
||||
b = InlineQuery(self.id_, User(1, '', False), '', '')
|
||||
c = InlineQuery(self.id_, User(0, '', False), '', '')
|
||||
d = InlineQuery(0, User(1, '', False), '', '')
|
||||
e = Update(self.id)
|
||||
e = Update(self.id_)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineKeyboardMarkup, InlineQueryResultAudio, InlineQueryR
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_article():
|
||||
return InlineQueryResultArticle(
|
||||
TestInlineQueryResultArticle.id,
|
||||
TestInlineQueryResultArticle.id_,
|
||||
TestInlineQueryResultArticle.title,
|
||||
input_message_content=TestInlineQueryResultArticle.input_message_content,
|
||||
reply_markup=TestInlineQueryResultArticle.reply_markup,
|
||||
@@ -39,8 +39,8 @@ def inline_query_result_article():
|
||||
|
||||
|
||||
class TestInlineQueryResultArticle(object):
|
||||
id = 'id'
|
||||
type = 'article'
|
||||
id_ = 'id'
|
||||
type_ = 'article'
|
||||
title = 'title'
|
||||
input_message_content = InputTextMessageContent('input_message_content')
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
@@ -52,8 +52,8 @@ class TestInlineQueryResultArticle(object):
|
||||
thumb_width = 15
|
||||
|
||||
def test_expected_values(self, inline_query_result_article):
|
||||
assert inline_query_result_article.type == self.type
|
||||
assert inline_query_result_article.id == self.id
|
||||
assert inline_query_result_article.type == self.type_
|
||||
assert inline_query_result_article.id == self.id_
|
||||
assert inline_query_result_article.title == self.title
|
||||
assert (inline_query_result_article.input_message_content.to_dict()
|
||||
== self.input_message_content.to_dict())
|
||||
@@ -88,11 +88,11 @@ class TestInlineQueryResultArticle(object):
|
||||
== inline_query_result_article.thumb_width)
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultArticle(self.id, self.title, self.input_message_content)
|
||||
b = InlineQueryResultArticle(self.id, self.title, self.input_message_content)
|
||||
c = InlineQueryResultArticle(self.id, '', self.input_message_content)
|
||||
a = InlineQueryResultArticle(self.id_, self.title, self.input_message_content)
|
||||
b = InlineQueryResultArticle(self.id_, self.title, self.input_message_content)
|
||||
c = InlineQueryResultArticle(self.id_, '', self.input_message_content)
|
||||
d = InlineQueryResultArticle('', self.title, self.input_message_content)
|
||||
e = InlineQueryResultAudio(self.id, '', '')
|
||||
e = InlineQueryResultAudio(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineKeyboardMarkup, InlineKeyboardButton, InlineQueryRes
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_audio():
|
||||
return InlineQueryResultAudio(
|
||||
TestInlineQueryResultAudio.id,
|
||||
TestInlineQueryResultAudio.id_,
|
||||
TestInlineQueryResultAudio.audio_url,
|
||||
TestInlineQueryResultAudio.title,
|
||||
performer=TestInlineQueryResultAudio.performer,
|
||||
@@ -38,8 +38,8 @@ def inline_query_result_audio():
|
||||
|
||||
|
||||
class TestInlineQueryResultAudio(object):
|
||||
id = 'id'
|
||||
type = 'audio'
|
||||
id_ = 'id'
|
||||
type_ = 'audio'
|
||||
audio_url = 'audio url'
|
||||
title = 'title'
|
||||
performer = 'performer'
|
||||
@@ -50,8 +50,8 @@ class TestInlineQueryResultAudio(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_audio):
|
||||
assert inline_query_result_audio.type == self.type
|
||||
assert inline_query_result_audio.id == self.id
|
||||
assert inline_query_result_audio.type == self.type_
|
||||
assert inline_query_result_audio.id == self.id_
|
||||
assert inline_query_result_audio.audio_url == self.audio_url
|
||||
assert inline_query_result_audio.title == self.title
|
||||
assert inline_query_result_audio.performer == self.performer
|
||||
@@ -81,11 +81,11 @@ class TestInlineQueryResultAudio(object):
|
||||
== inline_query_result_audio.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultAudio(self.id, self.audio_url, self.title)
|
||||
b = InlineQueryResultAudio(self.id, self.title, self.title)
|
||||
c = InlineQueryResultAudio(self.id, '', self.title)
|
||||
a = InlineQueryResultAudio(self.id_, self.audio_url, self.title)
|
||||
b = InlineQueryResultAudio(self.id_, self.title, self.title)
|
||||
c = InlineQueryResultAudio(self.id_, '', self.title)
|
||||
d = InlineQueryResultAudio('', self.audio_url, self.title)
|
||||
e = InlineQueryResultVoice(self.id, '', '')
|
||||
e = InlineQueryResultVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InputTextMessageContent, InlineQueryResultCachedAudio, Inl
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_cached_audio():
|
||||
return InlineQueryResultCachedAudio(
|
||||
TestInlineQueryResultCachedAudio.id,
|
||||
TestInlineQueryResultCachedAudio.id_,
|
||||
TestInlineQueryResultCachedAudio.audio_file_id,
|
||||
caption=TestInlineQueryResultCachedAudio.caption,
|
||||
parse_mode=TestInlineQueryResultCachedAudio.parse_mode,
|
||||
@@ -35,8 +35,8 @@ def inline_query_result_cached_audio():
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedAudio(object):
|
||||
id = 'id'
|
||||
type = 'audio'
|
||||
id_ = 'id'
|
||||
type_ = 'audio'
|
||||
audio_file_id = 'audio file id'
|
||||
caption = 'caption'
|
||||
parse_mode = 'HTML'
|
||||
@@ -44,8 +44,8 @@ class TestInlineQueryResultCachedAudio(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_cached_audio):
|
||||
assert inline_query_result_cached_audio.type == self.type
|
||||
assert inline_query_result_cached_audio.id == self.id
|
||||
assert inline_query_result_cached_audio.type == self.type_
|
||||
assert inline_query_result_cached_audio.id == self.id_
|
||||
assert inline_query_result_cached_audio.audio_file_id == self.audio_file_id
|
||||
assert inline_query_result_cached_audio.caption == self.caption
|
||||
assert inline_query_result_cached_audio.parse_mode == self.parse_mode
|
||||
@@ -73,11 +73,11 @@ class TestInlineQueryResultCachedAudio(object):
|
||||
== inline_query_result_cached_audio.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultCachedAudio(self.id, self.audio_file_id)
|
||||
b = InlineQueryResultCachedAudio(self.id, self.audio_file_id)
|
||||
c = InlineQueryResultCachedAudio(self.id, '')
|
||||
a = InlineQueryResultCachedAudio(self.id_, self.audio_file_id)
|
||||
b = InlineQueryResultCachedAudio(self.id_, self.audio_file_id)
|
||||
c = InlineQueryResultCachedAudio(self.id_, '')
|
||||
d = InlineQueryResultCachedAudio('', self.audio_file_id)
|
||||
e = InlineQueryResultCachedVoice(self.id, '', '')
|
||||
e = InlineQueryResultCachedVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineQueryResultCachedDocument, InlineKeyboardButton, Inl
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_cached_document():
|
||||
return InlineQueryResultCachedDocument(
|
||||
TestInlineQueryResultCachedDocument.id,
|
||||
TestInlineQueryResultCachedDocument.id_,
|
||||
TestInlineQueryResultCachedDocument.title,
|
||||
TestInlineQueryResultCachedDocument.document_file_id,
|
||||
caption=TestInlineQueryResultCachedDocument.caption,
|
||||
@@ -37,8 +37,8 @@ def inline_query_result_cached_document():
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedDocument(object):
|
||||
id = 'id'
|
||||
type = 'document'
|
||||
id_ = 'id'
|
||||
type_ = 'document'
|
||||
document_file_id = 'document file id'
|
||||
title = 'title'
|
||||
caption = 'caption'
|
||||
@@ -48,8 +48,8 @@ class TestInlineQueryResultCachedDocument(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_cached_document):
|
||||
assert inline_query_result_cached_document.id == self.id
|
||||
assert inline_query_result_cached_document.type == self.type
|
||||
assert inline_query_result_cached_document.id == self.id_
|
||||
assert inline_query_result_cached_document.type == self.type_
|
||||
assert inline_query_result_cached_document.document_file_id == self.document_file_id
|
||||
assert inline_query_result_cached_document.title == self.title
|
||||
assert inline_query_result_cached_document.caption == self.caption
|
||||
@@ -84,11 +84,11 @@ class TestInlineQueryResultCachedDocument(object):
|
||||
== inline_query_result_cached_document.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultCachedDocument(self.id, self.title, self.document_file_id)
|
||||
b = InlineQueryResultCachedDocument(self.id, self.title, self.document_file_id)
|
||||
c = InlineQueryResultCachedDocument(self.id, self.title, '')
|
||||
a = InlineQueryResultCachedDocument(self.id_, self.title, self.document_file_id)
|
||||
b = InlineQueryResultCachedDocument(self.id_, self.title, self.document_file_id)
|
||||
c = InlineQueryResultCachedDocument(self.id_, self.title, '')
|
||||
d = InlineQueryResultCachedDocument('', self.title, self.document_file_id)
|
||||
e = InlineQueryResultCachedVoice(self.id, '', '')
|
||||
e = InlineQueryResultCachedVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineKeyboardButton, InputTextMessageContent, InlineQuery
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_cached_gif():
|
||||
return InlineQueryResultCachedGif(
|
||||
TestInlineQueryResultCachedGif.id,
|
||||
TestInlineQueryResultCachedGif.id_,
|
||||
TestInlineQueryResultCachedGif.gif_file_id,
|
||||
title=TestInlineQueryResultCachedGif.title,
|
||||
caption=TestInlineQueryResultCachedGif.caption,
|
||||
@@ -36,8 +36,8 @@ def inline_query_result_cached_gif():
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedGif(object):
|
||||
id = 'id'
|
||||
type = 'gif'
|
||||
id_ = 'id'
|
||||
type_ = 'gif'
|
||||
gif_file_id = 'gif file id'
|
||||
title = 'title'
|
||||
caption = 'caption'
|
||||
@@ -46,8 +46,8 @@ class TestInlineQueryResultCachedGif(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_cached_gif):
|
||||
assert inline_query_result_cached_gif.type == self.type
|
||||
assert inline_query_result_cached_gif.id == self.id
|
||||
assert inline_query_result_cached_gif.type == self.type_
|
||||
assert inline_query_result_cached_gif.id == self.id_
|
||||
assert inline_query_result_cached_gif.gif_file_id == self.gif_file_id
|
||||
assert inline_query_result_cached_gif.title == self.title
|
||||
assert inline_query_result_cached_gif.caption == self.caption
|
||||
@@ -75,11 +75,11 @@ class TestInlineQueryResultCachedGif(object):
|
||||
== inline_query_result_cached_gif.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultCachedGif(self.id, self.gif_file_id)
|
||||
b = InlineQueryResultCachedGif(self.id, self.gif_file_id)
|
||||
c = InlineQueryResultCachedGif(self.id, '')
|
||||
a = InlineQueryResultCachedGif(self.id_, self.gif_file_id)
|
||||
b = InlineQueryResultCachedGif(self.id_, self.gif_file_id)
|
||||
c = InlineQueryResultCachedGif(self.id_, '')
|
||||
d = InlineQueryResultCachedGif('', self.gif_file_id)
|
||||
e = InlineQueryResultCachedVoice(self.id, '', '')
|
||||
e = InlineQueryResultCachedVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineQueryResultCachedMpeg4Gif, InlineKeyboardButton,
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_cached_mpeg4_gif():
|
||||
return InlineQueryResultCachedMpeg4Gif(
|
||||
TestInlineQueryResultCachedMpeg4Gif.id,
|
||||
TestInlineQueryResultCachedMpeg4Gif.id_,
|
||||
TestInlineQueryResultCachedMpeg4Gif.mpeg4_file_id,
|
||||
title=TestInlineQueryResultCachedMpeg4Gif.title,
|
||||
caption=TestInlineQueryResultCachedMpeg4Gif.caption,
|
||||
@@ -36,8 +36,8 @@ def inline_query_result_cached_mpeg4_gif():
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedMpeg4Gif(object):
|
||||
id = 'id'
|
||||
type = 'mpeg4_gif'
|
||||
id_ = 'id'
|
||||
type_ = 'mpeg4_gif'
|
||||
mpeg4_file_id = 'mpeg4 file id'
|
||||
title = 'title'
|
||||
caption = 'caption'
|
||||
@@ -46,8 +46,8 @@ class TestInlineQueryResultCachedMpeg4Gif(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_cached_mpeg4_gif):
|
||||
assert inline_query_result_cached_mpeg4_gif.type == self.type
|
||||
assert inline_query_result_cached_mpeg4_gif.id == self.id
|
||||
assert inline_query_result_cached_mpeg4_gif.type == self.type_
|
||||
assert inline_query_result_cached_mpeg4_gif.id == self.id_
|
||||
assert inline_query_result_cached_mpeg4_gif.mpeg4_file_id == self.mpeg4_file_id
|
||||
assert inline_query_result_cached_mpeg4_gif.title == self.title
|
||||
assert inline_query_result_cached_mpeg4_gif.caption == self.caption
|
||||
@@ -79,11 +79,11 @@ class TestInlineQueryResultCachedMpeg4Gif(object):
|
||||
== inline_query_result_cached_mpeg4_gif.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultCachedMpeg4Gif(self.id, self.mpeg4_file_id)
|
||||
b = InlineQueryResultCachedMpeg4Gif(self.id, self.mpeg4_file_id)
|
||||
c = InlineQueryResultCachedMpeg4Gif(self.id, '')
|
||||
a = InlineQueryResultCachedMpeg4Gif(self.id_, self.mpeg4_file_id)
|
||||
b = InlineQueryResultCachedMpeg4Gif(self.id_, self.mpeg4_file_id)
|
||||
c = InlineQueryResultCachedMpeg4Gif(self.id_, '')
|
||||
d = InlineQueryResultCachedMpeg4Gif('', self.mpeg4_file_id)
|
||||
e = InlineQueryResultCachedVoice(self.id, '', '')
|
||||
e = InlineQueryResultCachedVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InputTextMessageContent, InlineQueryResultCachedPhoto, Inl
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_cached_photo():
|
||||
return InlineQueryResultCachedPhoto(
|
||||
TestInlineQueryResultCachedPhoto.id,
|
||||
TestInlineQueryResultCachedPhoto.id_,
|
||||
TestInlineQueryResultCachedPhoto.photo_file_id,
|
||||
title=TestInlineQueryResultCachedPhoto.title,
|
||||
description=TestInlineQueryResultCachedPhoto.description,
|
||||
@@ -37,8 +37,8 @@ def inline_query_result_cached_photo():
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedPhoto(object):
|
||||
id = 'id'
|
||||
type = 'photo'
|
||||
id_ = 'id'
|
||||
type_ = 'photo'
|
||||
photo_file_id = 'photo file id'
|
||||
title = 'title'
|
||||
description = 'description'
|
||||
@@ -48,8 +48,8 @@ class TestInlineQueryResultCachedPhoto(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_cached_photo):
|
||||
assert inline_query_result_cached_photo.type == self.type
|
||||
assert inline_query_result_cached_photo.id == self.id
|
||||
assert inline_query_result_cached_photo.type == self.type_
|
||||
assert inline_query_result_cached_photo.id == self.id_
|
||||
assert inline_query_result_cached_photo.photo_file_id == self.photo_file_id
|
||||
assert inline_query_result_cached_photo.title == self.title
|
||||
assert inline_query_result_cached_photo.description == self.description
|
||||
@@ -83,11 +83,11 @@ class TestInlineQueryResultCachedPhoto(object):
|
||||
== inline_query_result_cached_photo.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultCachedPhoto(self.id, self.photo_file_id)
|
||||
b = InlineQueryResultCachedPhoto(self.id, self.photo_file_id)
|
||||
c = InlineQueryResultCachedPhoto(self.id, '')
|
||||
a = InlineQueryResultCachedPhoto(self.id_, self.photo_file_id)
|
||||
b = InlineQueryResultCachedPhoto(self.id_, self.photo_file_id)
|
||||
c = InlineQueryResultCachedPhoto(self.id_, '')
|
||||
d = InlineQueryResultCachedPhoto('', self.photo_file_id)
|
||||
e = InlineQueryResultCachedVoice(self.id, '', '')
|
||||
e = InlineQueryResultCachedVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -27,22 +27,22 @@ from telegram import (InputTextMessageContent, InlineKeyboardButton,
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_cached_sticker():
|
||||
return InlineQueryResultCachedSticker(
|
||||
TestInlineQueryResultCachedSticker.id,
|
||||
TestInlineQueryResultCachedSticker.id_,
|
||||
TestInlineQueryResultCachedSticker.sticker_file_id,
|
||||
input_message_content=TestInlineQueryResultCachedSticker.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedSticker.reply_markup)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedSticker(object):
|
||||
id = 'id'
|
||||
type = 'sticker'
|
||||
id_ = 'id'
|
||||
type_ = 'sticker'
|
||||
sticker_file_id = 'sticker file id'
|
||||
input_message_content = InputTextMessageContent('input_message_content')
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_cached_sticker):
|
||||
assert inline_query_result_cached_sticker.type == self.type
|
||||
assert inline_query_result_cached_sticker.id == self.id
|
||||
assert inline_query_result_cached_sticker.type == self.type_
|
||||
assert inline_query_result_cached_sticker.id == self.id_
|
||||
assert inline_query_result_cached_sticker.sticker_file_id == self.sticker_file_id
|
||||
assert (inline_query_result_cached_sticker.input_message_content.to_dict()
|
||||
== self.input_message_content.to_dict())
|
||||
@@ -65,11 +65,11 @@ class TestInlineQueryResultCachedSticker(object):
|
||||
== inline_query_result_cached_sticker.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultCachedSticker(self.id, self.sticker_file_id)
|
||||
b = InlineQueryResultCachedSticker(self.id, self.sticker_file_id)
|
||||
c = InlineQueryResultCachedSticker(self.id, '')
|
||||
a = InlineQueryResultCachedSticker(self.id_, self.sticker_file_id)
|
||||
b = InlineQueryResultCachedSticker(self.id_, self.sticker_file_id)
|
||||
c = InlineQueryResultCachedSticker(self.id_, '')
|
||||
d = InlineQueryResultCachedSticker('', self.sticker_file_id)
|
||||
e = InlineQueryResultCachedVoice(self.id, '', '')
|
||||
e = InlineQueryResultCachedVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineKeyboardMarkup, InlineKeyboardButton, InputTextMessa
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_cached_video():
|
||||
return InlineQueryResultCachedVideo(
|
||||
TestInlineQueryResultCachedVideo.id,
|
||||
TestInlineQueryResultCachedVideo.id_,
|
||||
TestInlineQueryResultCachedVideo.video_file_id,
|
||||
TestInlineQueryResultCachedVideo.title,
|
||||
caption=TestInlineQueryResultCachedVideo.caption,
|
||||
@@ -37,8 +37,8 @@ def inline_query_result_cached_video():
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedVideo(object):
|
||||
id = 'id'
|
||||
type = 'video'
|
||||
id_ = 'id'
|
||||
type_ = 'video'
|
||||
video_file_id = 'video file id'
|
||||
title = 'title'
|
||||
caption = 'caption'
|
||||
@@ -48,8 +48,8 @@ class TestInlineQueryResultCachedVideo(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_cached_video):
|
||||
assert inline_query_result_cached_video.type == self.type
|
||||
assert inline_query_result_cached_video.id == self.id
|
||||
assert inline_query_result_cached_video.type == self.type_
|
||||
assert inline_query_result_cached_video.id == self.id_
|
||||
assert inline_query_result_cached_video.video_file_id == self.video_file_id
|
||||
assert inline_query_result_cached_video.title == self.title
|
||||
assert inline_query_result_cached_video.description == self.description
|
||||
@@ -83,11 +83,11 @@ class TestInlineQueryResultCachedVideo(object):
|
||||
== inline_query_result_cached_video.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultCachedVideo(self.id, self.video_file_id, self.title)
|
||||
b = InlineQueryResultCachedVideo(self.id, self.video_file_id, self.title)
|
||||
c = InlineQueryResultCachedVideo(self.id, '', self.title)
|
||||
a = InlineQueryResultCachedVideo(self.id_, self.video_file_id, self.title)
|
||||
b = InlineQueryResultCachedVideo(self.id_, self.video_file_id, self.title)
|
||||
c = InlineQueryResultCachedVideo(self.id_, '', self.title)
|
||||
d = InlineQueryResultCachedVideo('', self.video_file_id, self.title)
|
||||
e = InlineQueryResultCachedVoice(self.id, '', '')
|
||||
e = InlineQueryResultCachedVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineQueryResultCachedVoice, InlineKeyboardButton, Inline
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_cached_voice():
|
||||
return InlineQueryResultCachedVoice(
|
||||
TestInlineQueryResultCachedVoice.id,
|
||||
TestInlineQueryResultCachedVoice.id_,
|
||||
TestInlineQueryResultCachedVoice.voice_file_id,
|
||||
TestInlineQueryResultCachedVoice.title,
|
||||
caption=TestInlineQueryResultCachedVoice.caption,
|
||||
@@ -36,8 +36,8 @@ def inline_query_result_cached_voice():
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedVoice(object):
|
||||
id = 'id'
|
||||
type = 'voice'
|
||||
id_ = 'id'
|
||||
type_ = 'voice'
|
||||
voice_file_id = 'voice file id'
|
||||
title = 'title'
|
||||
caption = 'caption'
|
||||
@@ -46,8 +46,8 @@ class TestInlineQueryResultCachedVoice(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_cached_voice):
|
||||
assert inline_query_result_cached_voice.type == self.type
|
||||
assert inline_query_result_cached_voice.id == self.id
|
||||
assert inline_query_result_cached_voice.type == self.type_
|
||||
assert inline_query_result_cached_voice.id == self.id_
|
||||
assert inline_query_result_cached_voice.voice_file_id == self.voice_file_id
|
||||
assert inline_query_result_cached_voice.title == self.title
|
||||
assert inline_query_result_cached_voice.caption == self.caption
|
||||
@@ -78,11 +78,11 @@ class TestInlineQueryResultCachedVoice(object):
|
||||
== inline_query_result_cached_voice.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultCachedVoice(self.id, self.voice_file_id, self.title)
|
||||
b = InlineQueryResultCachedVoice(self.id, self.voice_file_id, self.title)
|
||||
c = InlineQueryResultCachedVoice(self.id, '', self.title)
|
||||
a = InlineQueryResultCachedVoice(self.id_, self.voice_file_id, self.title)
|
||||
b = InlineQueryResultCachedVoice(self.id_, self.voice_file_id, self.title)
|
||||
c = InlineQueryResultCachedVoice(self.id_, '', self.title)
|
||||
d = InlineQueryResultCachedVoice('', self.voice_file_id, self.title)
|
||||
e = InlineQueryResultCachedAudio(self.id, '', '')
|
||||
e = InlineQueryResultCachedAudio(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineQueryResultVoice, InputTextMessageContent, InlineKey
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_contact():
|
||||
return InlineQueryResultContact(
|
||||
TestInlineQueryResultContact.id,
|
||||
TestInlineQueryResultContact.id_,
|
||||
TestInlineQueryResultContact.phone_number,
|
||||
TestInlineQueryResultContact.first_name,
|
||||
last_name=TestInlineQueryResultContact.last_name,
|
||||
@@ -38,8 +38,8 @@ def inline_query_result_contact():
|
||||
|
||||
|
||||
class TestInlineQueryResultContact(object):
|
||||
id = 'id'
|
||||
type = 'contact'
|
||||
id_ = 'id'
|
||||
type_ = 'contact'
|
||||
phone_number = 'phone_number'
|
||||
first_name = 'first_name'
|
||||
last_name = 'last_name'
|
||||
@@ -50,8 +50,8 @@ class TestInlineQueryResultContact(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_contact):
|
||||
assert inline_query_result_contact.id == self.id
|
||||
assert inline_query_result_contact.type == self.type
|
||||
assert inline_query_result_contact.id == self.id_
|
||||
assert inline_query_result_contact.type == self.type_
|
||||
assert inline_query_result_contact.phone_number == self.phone_number
|
||||
assert inline_query_result_contact.first_name == self.first_name
|
||||
assert inline_query_result_contact.last_name == self.last_name
|
||||
@@ -86,11 +86,11 @@ class TestInlineQueryResultContact(object):
|
||||
== inline_query_result_contact.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultContact(self.id, self.phone_number, self.first_name)
|
||||
b = InlineQueryResultContact(self.id, self.phone_number, self.first_name)
|
||||
c = InlineQueryResultContact(self.id, '', self.first_name)
|
||||
a = InlineQueryResultContact(self.id_, self.phone_number, self.first_name)
|
||||
b = InlineQueryResultContact(self.id_, self.phone_number, self.first_name)
|
||||
c = InlineQueryResultContact(self.id_, '', self.first_name)
|
||||
d = InlineQueryResultContact('', self.phone_number, self.first_name)
|
||||
e = InlineQueryResultVoice(self.id, '', '')
|
||||
e = InlineQueryResultVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineKeyboardButton, InputTextMessageContent, InlineQuery
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_document():
|
||||
return InlineQueryResultDocument(
|
||||
TestInlineQueryResultDocument.id,
|
||||
TestInlineQueryResultDocument.id_,
|
||||
TestInlineQueryResultDocument.document_url,
|
||||
TestInlineQueryResultDocument.title,
|
||||
TestInlineQueryResultDocument.mime_type,
|
||||
@@ -41,8 +41,8 @@ def inline_query_result_document():
|
||||
|
||||
|
||||
class TestInlineQueryResultDocument(object):
|
||||
id = 'id'
|
||||
type = 'document'
|
||||
id_ = 'id'
|
||||
type_ = 'document'
|
||||
document_url = 'document url'
|
||||
title = 'title'
|
||||
caption = 'caption'
|
||||
@@ -56,8 +56,8 @@ class TestInlineQueryResultDocument(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_document):
|
||||
assert inline_query_result_document.id == self.id
|
||||
assert inline_query_result_document.type == self.type
|
||||
assert inline_query_result_document.id == self.id_
|
||||
assert inline_query_result_document.type == self.type_
|
||||
assert inline_query_result_document.document_url == self.document_url
|
||||
assert inline_query_result_document.title == self.title
|
||||
assert inline_query_result_document.caption == self.caption
|
||||
@@ -99,13 +99,13 @@ class TestInlineQueryResultDocument(object):
|
||||
== inline_query_result_document.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultDocument(self.id, self.document_url, self.title,
|
||||
a = InlineQueryResultDocument(self.id_, self.document_url, self.title,
|
||||
self.mime_type)
|
||||
b = InlineQueryResultDocument(self.id, self.document_url, self.title,
|
||||
b = InlineQueryResultDocument(self.id_, self.document_url, self.title,
|
||||
self.mime_type)
|
||||
c = InlineQueryResultDocument(self.id, '', self.title, self.mime_type)
|
||||
c = InlineQueryResultDocument(self.id_, '', self.title, self.mime_type)
|
||||
d = InlineQueryResultDocument('', self.document_url, self.title, self.mime_type)
|
||||
e = InlineQueryResultVoice(self.id, '', '')
|
||||
e = InlineQueryResultVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -25,20 +25,20 @@ from telegram import (InlineKeyboardButton, InlineQueryResultGame,
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_game():
|
||||
return InlineQueryResultGame(TestInlineQueryResultGame.id,
|
||||
return InlineQueryResultGame(TestInlineQueryResultGame.id_,
|
||||
TestInlineQueryResultGame.game_short_name,
|
||||
reply_markup=TestInlineQueryResultGame.reply_markup)
|
||||
|
||||
|
||||
class TestInlineQueryResultGame(object):
|
||||
id = 'id'
|
||||
type = 'game'
|
||||
id_ = 'id'
|
||||
type_ = 'game'
|
||||
game_short_name = 'game short name'
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_game):
|
||||
assert inline_query_result_game.type == self.type
|
||||
assert inline_query_result_game.id == self.id
|
||||
assert inline_query_result_game.type == self.type_
|
||||
assert inline_query_result_game.id == self.id_
|
||||
assert inline_query_result_game.game_short_name == self.game_short_name
|
||||
assert (inline_query_result_game.reply_markup.to_dict()
|
||||
== self.reply_markup.to_dict())
|
||||
@@ -55,11 +55,11 @@ class TestInlineQueryResultGame(object):
|
||||
== inline_query_result_game.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultGame(self.id, self.game_short_name)
|
||||
b = InlineQueryResultGame(self.id, self.game_short_name)
|
||||
c = InlineQueryResultGame(self.id, '')
|
||||
a = InlineQueryResultGame(self.id_, self.game_short_name)
|
||||
b = InlineQueryResultGame(self.id_, self.game_short_name)
|
||||
c = InlineQueryResultGame(self.id_, '')
|
||||
d = InlineQueryResultGame('', self.game_short_name)
|
||||
e = InlineQueryResultVoice(self.id, '', '')
|
||||
e = InlineQueryResultVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineKeyboardButton, InputTextMessageContent, InlineQuery
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_gif():
|
||||
return InlineQueryResultGif(
|
||||
TestInlineQueryResultGif.id,
|
||||
TestInlineQueryResultGif.id_,
|
||||
TestInlineQueryResultGif.gif_url,
|
||||
TestInlineQueryResultGif.thumb_url,
|
||||
gif_width=TestInlineQueryResultGif.gif_width,
|
||||
@@ -40,8 +40,8 @@ def inline_query_result_gif():
|
||||
|
||||
|
||||
class TestInlineQueryResultGif(object):
|
||||
id = 'id'
|
||||
type = 'gif'
|
||||
id_ = 'id'
|
||||
type_ = 'gif'
|
||||
gif_url = 'gif url'
|
||||
gif_width = 10
|
||||
gif_height = 15
|
||||
@@ -54,8 +54,8 @@ class TestInlineQueryResultGif(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_gif):
|
||||
assert inline_query_result_gif.type == self.type
|
||||
assert inline_query_result_gif.id == self.id
|
||||
assert inline_query_result_gif.type == self.type_
|
||||
assert inline_query_result_gif.id == self.id_
|
||||
assert inline_query_result_gif.gif_url == self.gif_url
|
||||
assert inline_query_result_gif.gif_width == self.gif_width
|
||||
assert inline_query_result_gif.gif_height == self.gif_height
|
||||
@@ -88,11 +88,11 @@ class TestInlineQueryResultGif(object):
|
||||
== inline_query_result_gif.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultGif(self.id, self.gif_url, self.thumb_url)
|
||||
b = InlineQueryResultGif(self.id, self.gif_url, self.thumb_url)
|
||||
c = InlineQueryResultGif(self.id, '', self.thumb_url)
|
||||
a = InlineQueryResultGif(self.id_, self.gif_url, self.thumb_url)
|
||||
b = InlineQueryResultGif(self.id_, self.gif_url, self.thumb_url)
|
||||
c = InlineQueryResultGif(self.id_, '', self.thumb_url)
|
||||
d = InlineQueryResultGif('', self.gif_url, self.thumb_url)
|
||||
e = InlineQueryResultVoice(self.id, '', '')
|
||||
e = InlineQueryResultVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InputTextMessageContent, InlineQueryResultLocation, Inline
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_location():
|
||||
return InlineQueryResultLocation(
|
||||
TestInlineQueryResultLocation.id,
|
||||
TestInlineQueryResultLocation.id_,
|
||||
TestInlineQueryResultLocation.latitude,
|
||||
TestInlineQueryResultLocation.longitude,
|
||||
TestInlineQueryResultLocation.title,
|
||||
@@ -39,8 +39,8 @@ def inline_query_result_location():
|
||||
|
||||
|
||||
class TestInlineQueryResultLocation(object):
|
||||
id = 'id'
|
||||
type = 'location'
|
||||
id_ = 'id'
|
||||
type_ = 'location'
|
||||
latitude = 0.0
|
||||
longitude = 1.0
|
||||
title = 'title'
|
||||
@@ -52,8 +52,8 @@ class TestInlineQueryResultLocation(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_location):
|
||||
assert inline_query_result_location.id == self.id
|
||||
assert inline_query_result_location.type == self.type
|
||||
assert inline_query_result_location.id == self.id_
|
||||
assert inline_query_result_location.type == self.type_
|
||||
assert inline_query_result_location.latitude == self.latitude
|
||||
assert inline_query_result_location.longitude == self.longitude
|
||||
assert inline_query_result_location.title == self.title
|
||||
@@ -90,11 +90,11 @@ class TestInlineQueryResultLocation(object):
|
||||
== inline_query_result_location.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultLocation(self.id, self.longitude, self.latitude, self.title)
|
||||
b = InlineQueryResultLocation(self.id, self.longitude, self.latitude, self.title)
|
||||
c = InlineQueryResultLocation(self.id, 0, self.latitude, self.title)
|
||||
a = InlineQueryResultLocation(self.id_, self.longitude, self.latitude, self.title)
|
||||
b = InlineQueryResultLocation(self.id_, self.longitude, self.latitude, self.title)
|
||||
c = InlineQueryResultLocation(self.id_, 0, self.latitude, self.title)
|
||||
d = InlineQueryResultLocation('', self.longitude, self.latitude, self.title)
|
||||
e = InlineQueryResultVoice(self.id, '', '')
|
||||
e = InlineQueryResultVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineQueryResultMpeg4Gif, InlineKeyboardButton, InlineQue
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_mpeg4_gif():
|
||||
return InlineQueryResultMpeg4Gif(
|
||||
TestInlineQueryResultMpeg4Gif.id,
|
||||
TestInlineQueryResultMpeg4Gif.id_,
|
||||
TestInlineQueryResultMpeg4Gif.mpeg4_url,
|
||||
TestInlineQueryResultMpeg4Gif.thumb_url,
|
||||
mpeg4_width=TestInlineQueryResultMpeg4Gif.mpeg4_width,
|
||||
@@ -40,8 +40,8 @@ def inline_query_result_mpeg4_gif():
|
||||
|
||||
|
||||
class TestInlineQueryResultMpeg4Gif(object):
|
||||
id = 'id'
|
||||
type = 'mpeg4_gif'
|
||||
id_ = 'id'
|
||||
type_ = 'mpeg4_gif'
|
||||
mpeg4_url = 'mpeg4 url'
|
||||
mpeg4_width = 10
|
||||
mpeg4_height = 15
|
||||
@@ -54,8 +54,8 @@ class TestInlineQueryResultMpeg4Gif(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_mpeg4_gif):
|
||||
assert inline_query_result_mpeg4_gif.type == self.type
|
||||
assert inline_query_result_mpeg4_gif.id == self.id
|
||||
assert inline_query_result_mpeg4_gif.type == self.type_
|
||||
assert inline_query_result_mpeg4_gif.id == self.id_
|
||||
assert inline_query_result_mpeg4_gif.mpeg4_url == self.mpeg4_url
|
||||
assert inline_query_result_mpeg4_gif.mpeg4_width == self.mpeg4_width
|
||||
assert inline_query_result_mpeg4_gif.mpeg4_height == self.mpeg4_height
|
||||
@@ -95,11 +95,11 @@ class TestInlineQueryResultMpeg4Gif(object):
|
||||
== inline_query_result_mpeg4_gif.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultMpeg4Gif(self.id, self.mpeg4_url, self.thumb_url)
|
||||
b = InlineQueryResultMpeg4Gif(self.id, self.mpeg4_url, self.thumb_url)
|
||||
c = InlineQueryResultMpeg4Gif(self.id, '', self.thumb_url)
|
||||
a = InlineQueryResultMpeg4Gif(self.id_, self.mpeg4_url, self.thumb_url)
|
||||
b = InlineQueryResultMpeg4Gif(self.id_, self.mpeg4_url, self.thumb_url)
|
||||
c = InlineQueryResultMpeg4Gif(self.id_, '', self.thumb_url)
|
||||
d = InlineQueryResultMpeg4Gif('', self.mpeg4_url, self.thumb_url)
|
||||
e = InlineQueryResultVoice(self.id, '', '')
|
||||
e = InlineQueryResultVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InputTextMessageContent, InlineKeyboardButton, InlineKeybo
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_photo():
|
||||
return InlineQueryResultPhoto(
|
||||
TestInlineQueryResultPhoto.id,
|
||||
TestInlineQueryResultPhoto.id_,
|
||||
TestInlineQueryResultPhoto.photo_url,
|
||||
TestInlineQueryResultPhoto.thumb_url,
|
||||
photo_width=TestInlineQueryResultPhoto.photo_width,
|
||||
@@ -40,8 +40,8 @@ def inline_query_result_photo():
|
||||
|
||||
|
||||
class TestInlineQueryResultPhoto(object):
|
||||
id = 'id'
|
||||
type = 'photo'
|
||||
id_ = 'id'
|
||||
type_ = 'photo'
|
||||
photo_url = 'photo url'
|
||||
photo_width = 10
|
||||
photo_height = 15
|
||||
@@ -54,8 +54,8 @@ class TestInlineQueryResultPhoto(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_photo):
|
||||
assert inline_query_result_photo.type == self.type
|
||||
assert inline_query_result_photo.id == self.id
|
||||
assert inline_query_result_photo.type == self.type_
|
||||
assert inline_query_result_photo.id == self.id_
|
||||
assert inline_query_result_photo.photo_url == self.photo_url
|
||||
assert inline_query_result_photo.photo_width == self.photo_width
|
||||
assert inline_query_result_photo.photo_height == self.photo_height
|
||||
@@ -91,11 +91,11 @@ class TestInlineQueryResultPhoto(object):
|
||||
== inline_query_result_photo.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultPhoto(self.id, self.photo_url, self.thumb_url)
|
||||
b = InlineQueryResultPhoto(self.id, self.photo_url, self.thumb_url)
|
||||
c = InlineQueryResultPhoto(self.id, '', self.thumb_url)
|
||||
a = InlineQueryResultPhoto(self.id_, self.photo_url, self.thumb_url)
|
||||
b = InlineQueryResultPhoto(self.id_, self.photo_url, self.thumb_url)
|
||||
c = InlineQueryResultPhoto(self.id_, '', self.thumb_url)
|
||||
d = InlineQueryResultPhoto('', self.photo_url, self.thumb_url)
|
||||
e = InlineQueryResultVoice(self.id, '', '')
|
||||
e = InlineQueryResultVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineQueryResultVoice, InputTextMessageContent, InlineKey
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_venue():
|
||||
return InlineQueryResultVenue(
|
||||
TestInlineQueryResultVenue.id,
|
||||
TestInlineQueryResultVenue.id_,
|
||||
TestInlineQueryResultVenue.latitude,
|
||||
TestInlineQueryResultVenue.longitude,
|
||||
TestInlineQueryResultVenue.title,
|
||||
@@ -41,8 +41,8 @@ def inline_query_result_venue():
|
||||
|
||||
|
||||
class TestInlineQueryResultVenue(object):
|
||||
id = 'id'
|
||||
type = 'venue'
|
||||
id_ = 'id'
|
||||
type_ = 'venue'
|
||||
latitude = 'latitude'
|
||||
longitude = 'longitude'
|
||||
title = 'title'
|
||||
@@ -56,8 +56,8 @@ class TestInlineQueryResultVenue(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_venue):
|
||||
assert inline_query_result_venue.id == self.id
|
||||
assert inline_query_result_venue.type == self.type
|
||||
assert inline_query_result_venue.id == self.id_
|
||||
assert inline_query_result_venue.type == self.type_
|
||||
assert inline_query_result_venue.latitude == self.latitude
|
||||
assert inline_query_result_venue.longitude == self.longitude
|
||||
assert inline_query_result_venue.title == self.title
|
||||
@@ -96,14 +96,14 @@ class TestInlineQueryResultVenue(object):
|
||||
== inline_query_result_venue.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultVenue(self.id, self.longitude, self.latitude, self.title,
|
||||
a = InlineQueryResultVenue(self.id_, self.longitude, self.latitude, self.title,
|
||||
self.address)
|
||||
b = InlineQueryResultVenue(self.id, self.longitude, self.latitude, self.title,
|
||||
b = InlineQueryResultVenue(self.id_, self.longitude, self.latitude, self.title,
|
||||
self.address)
|
||||
c = InlineQueryResultVenue(self.id, '', self.latitude, self.title, self.address)
|
||||
c = InlineQueryResultVenue(self.id_, '', self.latitude, self.title, self.address)
|
||||
d = InlineQueryResultVenue('', self.longitude, self.latitude, self.title,
|
||||
self.address)
|
||||
e = InlineQueryResultVoice(self.id, '', '')
|
||||
e = InlineQueryResultVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,7 +26,7 @@ from telegram import (InlineKeyboardButton, InputTextMessageContent, InlineQuery
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_video():
|
||||
return InlineQueryResultVideo(
|
||||
TestInlineQueryResultVideo.id,
|
||||
TestInlineQueryResultVideo.id_,
|
||||
TestInlineQueryResultVideo.video_url,
|
||||
TestInlineQueryResultVideo.mime_type,
|
||||
TestInlineQueryResultVideo.thumb_url,
|
||||
@@ -42,8 +42,8 @@ def inline_query_result_video():
|
||||
|
||||
|
||||
class TestInlineQueryResultVideo(object):
|
||||
id = 'id'
|
||||
type = 'video'
|
||||
id_ = 'id'
|
||||
type_ = 'video'
|
||||
video_url = 'video url'
|
||||
mime_type = 'mime type'
|
||||
video_width = 10
|
||||
@@ -58,8 +58,8 @@ class TestInlineQueryResultVideo(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_video):
|
||||
assert inline_query_result_video.type == self.type
|
||||
assert inline_query_result_video.id == self.id
|
||||
assert inline_query_result_video.type == self.type_
|
||||
assert inline_query_result_video.id == self.id_
|
||||
assert inline_query_result_video.video_url == self.video_url
|
||||
assert inline_query_result_video.mime_type == self.mime_type
|
||||
assert inline_query_result_video.video_width == self.video_width
|
||||
@@ -100,15 +100,15 @@ class TestInlineQueryResultVideo(object):
|
||||
== inline_query_result_video.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultVideo(self.id, self.video_url, self.mime_type,
|
||||
a = InlineQueryResultVideo(self.id_, self.video_url, self.mime_type,
|
||||
self.thumb_url, self.title)
|
||||
b = InlineQueryResultVideo(self.id, self.video_url, self.mime_type,
|
||||
b = InlineQueryResultVideo(self.id_, self.video_url, self.mime_type,
|
||||
self.thumb_url, self.title)
|
||||
c = InlineQueryResultVideo(self.id, '', self.mime_type, self.thumb_url,
|
||||
c = InlineQueryResultVideo(self.id_, '', self.mime_type, self.thumb_url,
|
||||
self.title)
|
||||
d = InlineQueryResultVideo('', self.video_url, self.mime_type, self.thumb_url,
|
||||
self.title)
|
||||
e = InlineQueryResultVoice(self.id, '', '')
|
||||
e = InlineQueryResultVoice(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
@@ -26,8 +26,8 @@ from telegram import (InlineKeyboardButton, InputTextMessageContent, InlineQuery
|
||||
@pytest.fixture(scope='class')
|
||||
def inline_query_result_voice():
|
||||
return InlineQueryResultVoice(
|
||||
type=TestInlineQueryResultVoice.type,
|
||||
id=TestInlineQueryResultVoice.id,
|
||||
type=TestInlineQueryResultVoice.type_,
|
||||
id=TestInlineQueryResultVoice.id_,
|
||||
voice_url=TestInlineQueryResultVoice.voice_url,
|
||||
title=TestInlineQueryResultVoice.title,
|
||||
voice_duration=TestInlineQueryResultVoice.voice_duration,
|
||||
@@ -38,8 +38,8 @@ def inline_query_result_voice():
|
||||
|
||||
|
||||
class TestInlineQueryResultVoice(object):
|
||||
id = 'id'
|
||||
type = 'voice'
|
||||
id_ = 'id'
|
||||
type_ = 'voice'
|
||||
voice_url = 'voice url'
|
||||
title = 'title'
|
||||
voice_duration = 'voice_duration'
|
||||
@@ -49,8 +49,8 @@ class TestInlineQueryResultVoice(object):
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton('reply_markup')]])
|
||||
|
||||
def test_expected_values(self, inline_query_result_voice):
|
||||
assert inline_query_result_voice.type == self.type
|
||||
assert inline_query_result_voice.id == self.id
|
||||
assert inline_query_result_voice.type == self.type_
|
||||
assert inline_query_result_voice.id == self.id_
|
||||
assert inline_query_result_voice.voice_url == self.voice_url
|
||||
assert inline_query_result_voice.title == self.title
|
||||
assert inline_query_result_voice.voice_duration == self.voice_duration
|
||||
@@ -78,11 +78,11 @@ class TestInlineQueryResultVoice(object):
|
||||
== inline_query_result_voice.reply_markup.to_dict())
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultVoice(self.id, self.voice_url, self.title)
|
||||
b = InlineQueryResultVoice(self.id, self.voice_url, self.title)
|
||||
c = InlineQueryResultVoice(self.id, '', self.title)
|
||||
a = InlineQueryResultVoice(self.id_, self.voice_url, self.title)
|
||||
b = InlineQueryResultVoice(self.id_, self.voice_url, self.title)
|
||||
c = InlineQueryResultVoice(self.id_, '', self.title)
|
||||
d = InlineQueryResultVoice('', self.voice_url, self.title)
|
||||
e = InlineQueryResultAudio(self.id, '', '')
|
||||
e = InlineQueryResultAudio(self.id_, '', '')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
+20
-20
@@ -83,7 +83,7 @@ def input_media_document(class_thumb_file):
|
||||
|
||||
|
||||
class TestInputMediaVideo(object):
|
||||
type = "video"
|
||||
type_ = "video"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
width = 3
|
||||
@@ -93,7 +93,7 @@ class TestInputMediaVideo(object):
|
||||
supports_streaming = True
|
||||
|
||||
def test_expected_values(self, input_media_video):
|
||||
assert input_media_video.type == self.type
|
||||
assert input_media_video.type == self.type_
|
||||
assert input_media_video.media == self.media
|
||||
assert input_media_video.caption == self.caption
|
||||
assert input_media_video.width == self.width
|
||||
@@ -117,7 +117,7 @@ class TestInputMediaVideo(object):
|
||||
def test_with_video(self, video): # noqa: F811
|
||||
# fixture found in test_video
|
||||
input_media_video = InputMediaVideo(video, caption="test 3")
|
||||
assert input_media_video.type == self.type
|
||||
assert input_media_video.type == self.type_
|
||||
assert input_media_video.media == video.file_id
|
||||
assert input_media_video.width == video.width
|
||||
assert input_media_video.height == video.height
|
||||
@@ -127,19 +127,19 @@ class TestInputMediaVideo(object):
|
||||
def test_with_video_file(self, video_file): # noqa: F811
|
||||
# fixture found in test_video
|
||||
input_media_video = InputMediaVideo(video_file, caption="test 3")
|
||||
assert input_media_video.type == self.type
|
||||
assert input_media_video.type == self.type_
|
||||
assert isinstance(input_media_video.media, InputFile)
|
||||
assert input_media_video.caption == "test 3"
|
||||
|
||||
|
||||
class TestInputMediaPhoto(object):
|
||||
type = "photo"
|
||||
type_ = "photo"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
parse_mode = 'Markdown'
|
||||
|
||||
def test_expected_values(self, input_media_photo):
|
||||
assert input_media_photo.type == self.type
|
||||
assert input_media_photo.type == self.type_
|
||||
assert input_media_photo.media == self.media
|
||||
assert input_media_photo.caption == self.caption
|
||||
assert input_media_photo.parse_mode == self.parse_mode
|
||||
@@ -154,20 +154,20 @@ class TestInputMediaPhoto(object):
|
||||
def test_with_photo(self, photo): # noqa: F811
|
||||
# fixture found in test_photo
|
||||
input_media_photo = InputMediaPhoto(photo, caption="test 2")
|
||||
assert input_media_photo.type == self.type
|
||||
assert input_media_photo.type == self.type_
|
||||
assert input_media_photo.media == photo.file_id
|
||||
assert input_media_photo.caption == "test 2"
|
||||
|
||||
def test_with_photo_file(self, photo_file): # noqa: F811
|
||||
# fixture found in test_photo
|
||||
input_media_photo = InputMediaPhoto(photo_file, caption="test 2")
|
||||
assert input_media_photo.type == self.type
|
||||
assert input_media_photo.type == self.type_
|
||||
assert isinstance(input_media_photo.media, InputFile)
|
||||
assert input_media_photo.caption == "test 2"
|
||||
|
||||
|
||||
class TestInputMediaAnimation(object):
|
||||
type = "animation"
|
||||
type_ = "animation"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
parse_mode = 'Markdown'
|
||||
@@ -176,7 +176,7 @@ class TestInputMediaAnimation(object):
|
||||
duration = 1
|
||||
|
||||
def test_expected_values(self, input_media_animation):
|
||||
assert input_media_animation.type == self.type
|
||||
assert input_media_animation.type == self.type_
|
||||
assert input_media_animation.media == self.media
|
||||
assert input_media_animation.caption == self.caption
|
||||
assert input_media_animation.parse_mode == self.parse_mode
|
||||
@@ -195,20 +195,20 @@ class TestInputMediaAnimation(object):
|
||||
def test_with_animation(self, animation): # noqa: F811
|
||||
# fixture found in test_animation
|
||||
input_media_animation = InputMediaAnimation(animation, caption="test 2")
|
||||
assert input_media_animation.type == self.type
|
||||
assert input_media_animation.type == self.type_
|
||||
assert input_media_animation.media == animation.file_id
|
||||
assert input_media_animation.caption == "test 2"
|
||||
|
||||
def test_with_animation_file(self, animation_file): # noqa: F811
|
||||
# fixture found in test_animation
|
||||
input_media_animation = InputMediaAnimation(animation_file, caption="test 2")
|
||||
assert input_media_animation.type == self.type
|
||||
assert input_media_animation.type == self.type_
|
||||
assert isinstance(input_media_animation.media, InputFile)
|
||||
assert input_media_animation.caption == "test 2"
|
||||
|
||||
|
||||
class TestInputMediaAudio(object):
|
||||
type = "audio"
|
||||
type_ = "audio"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
duration = 3
|
||||
@@ -217,7 +217,7 @@ class TestInputMediaAudio(object):
|
||||
parse_mode = 'HTML'
|
||||
|
||||
def test_expected_values(self, input_media_audio):
|
||||
assert input_media_audio.type == self.type
|
||||
assert input_media_audio.type == self.type_
|
||||
assert input_media_audio.media == self.media
|
||||
assert input_media_audio.caption == self.caption
|
||||
assert input_media_audio.duration == self.duration
|
||||
@@ -239,7 +239,7 @@ class TestInputMediaAudio(object):
|
||||
def test_with_audio(self, audio): # noqa: F811
|
||||
# fixture found in test_audio
|
||||
input_media_audio = InputMediaAudio(audio, caption="test 3")
|
||||
assert input_media_audio.type == self.type
|
||||
assert input_media_audio.type == self.type_
|
||||
assert input_media_audio.media == audio.file_id
|
||||
assert input_media_audio.duration == audio.duration
|
||||
assert input_media_audio.performer == audio.performer
|
||||
@@ -249,19 +249,19 @@ class TestInputMediaAudio(object):
|
||||
def test_with_audio_file(self, audio_file): # noqa: F811
|
||||
# fixture found in test_audio
|
||||
input_media_audio = InputMediaAudio(audio_file, caption="test 3")
|
||||
assert input_media_audio.type == self.type
|
||||
assert input_media_audio.type == self.type_
|
||||
assert isinstance(input_media_audio.media, InputFile)
|
||||
assert input_media_audio.caption == "test 3"
|
||||
|
||||
|
||||
class TestInputMediaDocument(object):
|
||||
type = "document"
|
||||
type_ = "document"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
parse_mode = 'HTML'
|
||||
|
||||
def test_expected_values(self, input_media_document):
|
||||
assert input_media_document.type == self.type
|
||||
assert input_media_document.type == self.type_
|
||||
assert input_media_document.media == self.media
|
||||
assert input_media_document.caption == self.caption
|
||||
assert input_media_document.parse_mode == self.parse_mode
|
||||
@@ -277,14 +277,14 @@ class TestInputMediaDocument(object):
|
||||
def test_with_document(self, document): # noqa: F811
|
||||
# fixture found in test_document
|
||||
input_media_document = InputMediaDocument(document, caption="test 3")
|
||||
assert input_media_document.type == self.type
|
||||
assert input_media_document.type == self.type_
|
||||
assert input_media_document.media == document.file_id
|
||||
assert input_media_document.caption == "test 3"
|
||||
|
||||
def test_with_document_file(self, document_file): # noqa: F811
|
||||
# fixture found in test_document
|
||||
input_media_document = InputMediaDocument(document_file, caption="test 3")
|
||||
assert input_media_document.type == self.type
|
||||
assert input_media_document.type == self.type_
|
||||
assert isinstance(input_media_document.media, InputFile)
|
||||
assert input_media_document.caption == "test 3"
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ def job_queue(bot, _dp):
|
||||
jq.stop()
|
||||
|
||||
|
||||
@pytest.mark.skipif(os.getenv('APPVEYOR'), reason="On Appveyor precise timings are not accurate.")
|
||||
@pytest.mark.skipif(os.getenv('GITHUB_ACTIONS', False) and os.name == 'nt',
|
||||
reason="On windows precise timings are not accurate.")
|
||||
@flaky(10, 1) # Timings aren't quite perfect
|
||||
|
||||
@@ -20,24 +20,28 @@
|
||||
import pytest
|
||||
|
||||
from telegram import KeyboardButton
|
||||
from telegram.keyboardbuttonpolltype import KeyboardButtonPollType
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def keyboard_button():
|
||||
return KeyboardButton(TestKeyboardButton.text,
|
||||
request_location=TestKeyboardButton.request_location,
|
||||
request_contact=TestKeyboardButton.request_contact)
|
||||
request_contact=TestKeyboardButton.request_contact,
|
||||
request_poll=TestKeyboardButton.request_poll)
|
||||
|
||||
|
||||
class TestKeyboardButton(object):
|
||||
text = 'text'
|
||||
request_location = True
|
||||
request_contact = True
|
||||
request_poll = KeyboardButtonPollType("quiz")
|
||||
|
||||
def test_expected_values(self, keyboard_button):
|
||||
assert keyboard_button.text == self.text
|
||||
assert keyboard_button.request_location == self.request_location
|
||||
assert keyboard_button.request_contact == self.request_contact
|
||||
assert keyboard_button.request_poll == self.request_poll
|
||||
|
||||
def test_to_dict(self, keyboard_button):
|
||||
keyboard_button_dict = keyboard_button.to_dict()
|
||||
@@ -46,3 +50,4 @@ class TestKeyboardButton(object):
|
||||
assert keyboard_button_dict['text'] == keyboard_button.text
|
||||
assert keyboard_button_dict['request_location'] == keyboard_button.request_location
|
||||
assert keyboard_button_dict['request_contact'] == keyboard_button.request_contact
|
||||
assert keyboard_button_dict['request_poll'] == keyboard_button.request_poll.to_dict()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user