mirror of
https://github.com/eternnoir/pyTelegramBotAPI.git
synced 2023-08-10 21:12:57 +03:00
Compare commits
261 Commits
Author | SHA1 | Date | |
---|---|---|---|
b1e5d00821 | |||
aa02ddb573 | |||
760ea5a2f0 | |||
9b279dc562 | |||
5cd97ebc96 | |||
b5ba2445d3 | |||
7adec8bd90 | |||
0603a0df4c | |||
59810b5e2a | |||
b999fea2ac | |||
a41dabf73c | |||
5407801f62 | |||
2efb33fc29 | |||
620ea5dee0 | |||
eaf44f1a6b | |||
8c62b99057 | |||
e3b126807e | |||
769ff8008e | |||
0e0e2d97c0 | |||
bb199024fd | |||
86644c05f7 | |||
3a3bab5b92 | |||
bf844ed202 | |||
fefb9d4555 | |||
a413a51221 | |||
a71030dcdd | |||
68db599790 | |||
a749acde15 | |||
5935a378ca | |||
1dd94d6e6d | |||
2fb0f3fb4b | |||
575fb9da7f | |||
c6358f35d2 | |||
20b87f2242 | |||
f4c215b0b8 | |||
1a30a9a249 | |||
e644ed910a | |||
8cb2da3775 | |||
f8e7c0f819 | |||
f241ef1eac | |||
8f8276314e | |||
9e30cfbda6 | |||
6fb9e18385 | |||
f0835a1a14 | |||
be3b6f88e8 | |||
87e811ce3e | |||
151880f391 | |||
bf91829088 | |||
56f0b0a0d4 | |||
2b8e77f749 | |||
fba425265e | |||
23069ac729 | |||
7ab93f55a6 | |||
ba2705dc82 | |||
3a1bdc2899 | |||
4e57adbcb6 | |||
600002e158 | |||
3c62e9d391 | |||
63df69aeb8 | |||
a8cf9f4ae5 | |||
b10e45f714 | |||
9624b45314 | |||
e26ad07965 | |||
55c7b6373c | |||
ceceeb7d8c | |||
b76a69e036 | |||
e5700380bd | |||
47b53b8812 | |||
2d0ebde481 | |||
271b7e0642 | |||
f516438360 | |||
7dc9abffc6 | |||
2285d0466e | |||
31dbe30489 | |||
c77307881d | |||
1a58731fb7 | |||
99df992a66 | |||
79e6a3166d | |||
8005ca2f6c | |||
b82ed70ec9 | |||
18e37f3d20 | |||
ceea457cf1 | |||
4131b05733 | |||
ad4be5c0ae | |||
a946b79839 | |||
4eeca78f2f | |||
2d6c2a345f | |||
e62eeb7ff2 | |||
76fc8fbe5e | |||
584955962e | |||
b8f442d06b | |||
891988be93 | |||
8636b282d7 | |||
2c57c5c01c | |||
07b82dc9b0 | |||
a850a0d94f | |||
d4f1444503 | |||
bab9f7bbb9 | |||
d9ace2adc8 | |||
36621bb22a | |||
99466017c5 | |||
feec1dde56 | |||
54eba946be | |||
65a272b901 | |||
6a4c7e731b | |||
2b3c86b647 | |||
e419214b49 | |||
fe6959c38e | |||
7dd53b1396 | |||
421118d9d8 | |||
cf69a06ab8 | |||
8ac6e664c5 | |||
12dbcb56d3 | |||
a46975d038 | |||
494b535a91 | |||
74f75884f3 | |||
4eae469528 | |||
41f7c07959 | |||
35ea2a2b7e | |||
522b2b487b | |||
5035e0ce80 | |||
7061091c1c | |||
5c199bd246 | |||
44dd89881d | |||
8634e65249 | |||
76dbb05259 | |||
578a9383b2 | |||
85093bded5 | |||
27d442fabf | |||
f251def304 | |||
2b822f782d | |||
8bc5b74495 | |||
70426ac274 | |||
a3a2bd5793 | |||
c3b6ee9dc0 | |||
4079772fd3 | |||
9547a8d7b1 | |||
c8b2b14157 | |||
3d5ef5b1d8 | |||
776a699a8d | |||
78afd045d8 | |||
06faed887c | |||
bc855f7610 | |||
893d5386c5 | |||
909d570dca | |||
424c77fd2c | |||
333949683f | |||
fa038c2e42 | |||
d61de35a32 | |||
13df7b5908 | |||
1de356dcc3 | |||
47e6dfd6bc | |||
3c890a7846 | |||
17971ff48b | |||
b989b7601b | |||
8c574a786a | |||
7e5f51e4ab | |||
018e4597a2 | |||
7df6b3d4c9 | |||
4facc5f7d7 | |||
4bcfc34a50 | |||
b1d5cb2129 | |||
00c8dcc19b | |||
ed7e33b4c6 | |||
74a952846c | |||
e99fb8f84f | |||
49aee14fca | |||
9267da205d | |||
9c79ba2f87 | |||
3be21ae361 | |||
42343c3a7f | |||
5a102ed8fa | |||
e1e109bef1 | |||
b5a217013a | |||
3ba9799b98 | |||
91f213ff34 | |||
8f55460924 | |||
f6b999053d | |||
99ff104a3f | |||
662c2c8797 | |||
72a0199a2f | |||
989cae597b | |||
5dd88f8223 | |||
28111bdf4e | |||
10ec897fb5 | |||
ffe3a0c3d7 | |||
f5f48db6ba | |||
183230e927 | |||
7957bc45a8 | |||
373d4d37ff | |||
0d0e37dae5 | |||
36d088dfbf | |||
9ae20b4815 | |||
e761e1e1d9 | |||
cb0256b37d | |||
ff3cbaf45b | |||
d231b1fbaa | |||
7f47f11444 | |||
0422e62f65 | |||
82e252ec46 | |||
c11a9f810c | |||
d17d28a144 | |||
dadcd5a577 | |||
afc9abc269 | |||
e01f17e3a0 | |||
48e6757686 | |||
8495229ce1 | |||
3b60f7ca67 | |||
a1930e05c2 | |||
bc067662dc | |||
518c49f23a | |||
903b1dfd50 | |||
2e199a5684 | |||
55302cb972 | |||
f47653d2e4 | |||
94b4a25980 | |||
afac177d7d | |||
2637e29dbe | |||
6d180e30f0 | |||
e2ed4cf065 | |||
8b2dea1d56 | |||
41e31de034 | |||
ae074fd5c9 | |||
60596a95b8 | |||
44531bcedf | |||
8aa8fa5986 | |||
f0e64b3653 | |||
8444ea588a | |||
b2f376a906 | |||
d0b4bb7c69 | |||
c300195b49 | |||
2493b200a4 | |||
8528ca9e4e | |||
e1a3ccadb7 | |||
a43f037bc9 | |||
7ac246b801 | |||
47624a556e | |||
8bdbc24014 | |||
e45ced958a | |||
46c803bf55 | |||
3986f33d3a | |||
c327be5a03 | |||
d8587419e1 | |||
35d7293ebd | |||
8e71a612a6 | |||
5f8d99664e | |||
aaa968c27f | |||
600c014515 | |||
0a80fafd76 | |||
4a11bb60b4 | |||
7d37374667 | |||
6ad56eb30f | |||
211f1c607d | |||
be786021dc | |||
15d287919d | |||
af991ea76e | |||
064b84ad3d | |||
39b4f0a068 | |||
246e7e31d7 | |||
48bfb7b84f | |||
e92dc3717e |
@ -1,10 +1,10 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.6"
|
||||
- "2.7"
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
- "3.5"
|
||||
- "3.6"
|
||||
- "3.7"
|
||||
- "3.8"
|
||||
- "pypy"
|
||||
- "pypy3"
|
||||
install: "pip install -r requirements.txt"
|
||||
|
52
README.md
52
README.md
@ -26,6 +26,7 @@
|
||||
* [Using web hooks](#using-web-hooks)
|
||||
* [Logging](#logging)
|
||||
* [Proxy](#proxy)
|
||||
* [New in library](#new-in-library)
|
||||
* [F.A.Q.](#faq)
|
||||
* [Bot 2.0](#bot-20)
|
||||
* [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)
|
||||
@ -124,7 +125,7 @@ To start the bot, simply open up a terminal and enter `python echo_bot.py` to ru
|
||||
All types are defined in types.py. They are all completely in line with the [Telegram API's definition of the types](https://core.telegram.org/bots/api#available-types), except for the Message's `from` field, which is renamed to `from_user` (because `from` is a Python reserved token). Thus, attributes such as `message_id` can be accessed directly with `message.message_id`. Note that `message.chat` can be either an instance of `User` or `GroupChat` (see [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)).
|
||||
|
||||
The Message object also has a `content_type`attribute, which defines the type of the Message. `content_type` can be one of the following strings:
|
||||
`text`, `audio`, `document`, `photo`, `sticker`, `video`, `video_note`, `voice`, `location`, `contact`, `new_chat_member`, `left_chat_member`, `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`, `supergroup_chat_created`, `channel_chat_created`, `migrate_to_chat_id`, `migrate_from_chat_id`, `pinned_message`.
|
||||
`text`, `audio`, `document`, `photo`, `sticker`, `video`, `video_note`, `voice`, `location`, `contact`, `new_chat_members`, `left_chat_member`, `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`, `supergroup_chat_created`, `channel_chat_created`, `migrate_to_chat_id`, `migrate_from_chat_id`, `pinned_message`.
|
||||
|
||||
You can use some types in one function. Example:
|
||||
|
||||
@ -250,7 +251,7 @@ updates = tb.get_updates()
|
||||
updates = tb.get_updates(1234,100,20) #get_Updates(offset, limit, timeout):
|
||||
|
||||
# sendMessage
|
||||
tb.send_message(chatid, text)
|
||||
tb.send_message(chat_id, text)
|
||||
|
||||
# forwardMessage
|
||||
tb.forward_message(to_chat_id, from_chat_id, message_id)
|
||||
@ -291,8 +292,8 @@ tb.send_video(chat_id, "FILEID")
|
||||
|
||||
# sendVideoNote
|
||||
videonote = open('/tmp/videonote.mp4', 'rb')
|
||||
tb.send_video(chat_id, videonote)
|
||||
tb.send_video(chat_id, "FILEID")
|
||||
tb.send_video_note(chat_id, videonote)
|
||||
tb.send_video_note(chat_id, "FILEID")
|
||||
|
||||
# sendLocation
|
||||
tb.send_location(chat_id, lat, lon)
|
||||
@ -500,19 +501,20 @@ You can use proxy for request. `apihelper.proxy` object will use by call `reques
|
||||
```python
|
||||
from telebot import apihelper
|
||||
|
||||
apihelper.proxy = {'http', 'http://10.10.1.10:3128'}
|
||||
apihelper.proxy = {'http':'http://10.10.1.10:3128'}
|
||||
```
|
||||
|
||||
If you want to use socket5 proxy you need install dependency `pip install requests[socks]`.
|
||||
If you want to use socket5 proxy you need install dependency `pip install requests[socks]` and make sure, that you have the latest version of `gunicorn`, `PySocks`, `pyTelegramBotAPI`, `requests` and `urllib3`.
|
||||
|
||||
```python
|
||||
proxies = {
|
||||
'http': 'socks5://user:pass@host:port',
|
||||
'https': 'socks5://user:pass@host:port'
|
||||
}
|
||||
apihelper.proxy = {'https':'socks5://userproxy:password@proxy_address:port'}
|
||||
```
|
||||
|
||||
|
||||
## New in library
|
||||
|
||||
06.06.2019 - Добавленна поддержка опросов (Poll). Добавлены функции send_poll, stop_poll
|
||||
|
||||
## F.A.Q.
|
||||
|
||||
### Bot 2.0
|
||||
@ -527,16 +529,16 @@ Telegram Bot API support new type Chat for message.chat.
|
||||
- Check the ```type``` attribute in ```Chat``` object:
|
||||
-
|
||||
```python
|
||||
if message.chat.type == “private”:
|
||||
if message.chat.type == "private":
|
||||
# private chat message
|
||||
|
||||
if message.chat.type == “group”:
|
||||
if message.chat.type == "group":
|
||||
# group chat message
|
||||
|
||||
if message.chat.type == “supergroup”:
|
||||
if message.chat.type == "supergroup":
|
||||
# supergroup chat message
|
||||
|
||||
if message.chat.type == “channel”:
|
||||
if message.chat.type == "channel":
|
||||
# channel message
|
||||
|
||||
```
|
||||
@ -564,7 +566,7 @@ Get help. Discuss. Chat.
|
||||
* [Telegram Proxy Bot](https://github.com/mrgigabyte/proxybot) by *mrgigabyte* - `Credits for the original version of this bot goes to` **Groosha** `, simply added certain features which I thought were needed`.
|
||||
* [RadRetroRobot](https://github.com/Tronikart/RadRetroRobot) by *Tronikart* - Multifunctional Telegram Bot RadRetroRobot.
|
||||
* [League of Legends bot](https://telegram.me/League_of_Legends_bot) ([source](https://github.com/i32ropie/lol)) by *i32ropie*
|
||||
* [NeoBot](https://github.com/neoranger/NeoBot) by *neoranger*
|
||||
* [NeoBot](https://github.com/neoranger/NeoBot) by [@NeoRanger](https://github.com/neoranger)
|
||||
* [TagAlertBot](https://github.com/pitasi/TagAlertBot) by *pitasi*
|
||||
* [ComedoresUGRbot](http://telegram.me/ComedoresUGRbot) ([source](https://github.com/alejandrocq/ComedoresUGRbot)) by [*alejandrocq*](https://github.com/alejandrocq) - Telegram bot to check the menu of Universidad de Granada dining hall.
|
||||
* [picpingbot](https://web.telegram.org/#/im?p=%40picpingbot) - Fun anonymous photo exchange by Boogie Muffin.
|
||||
@ -579,6 +581,24 @@ Get help. Discuss. Chat.
|
||||
* [EmaProject](https://github.com/halkliff/emaproject) by [*halkliff*](https://github.com/halkliff) - Ema - Eastern Media Assistant was made thinking on the ease-to-use feature. Coding here is simple, as much as is fast and powerful.
|
||||
* [filmratingbot](http://t.me/filmratingbot)([source](https://github.com/jcolladosp/film-rating-bot)) by [*jcolladosp*](https://github.com/jcolladosp) - Telegram bot using the Python API that gets films rating from IMDb and metacritic
|
||||
* [you2mp3bot](http://t.me/you2mp3bot)([link](https://storebot.me/bot/you2mp3bot)) - This bot can convert a Youtube video to Mp3. All you need is send the URL video.
|
||||
* [areajugonesbot](http://t.me/areajugonesbot)([link](http://t.me/areajugonesbot)) - The areajugonesbot sends news published on the videogames blog Areajugones to Telegram.
|
||||
* [Send2Kindlebot](http://t.me/Send2KindleBot) ([source](https://github.com/GabrielRF/Send2KindleBot)) by *GabrielRF* - Send to Kindle service.
|
||||
* [RastreioBot](http://t.me/RastreioBot) ([source](https://github.com/GabrielRF/RastreioBot)) by *GabrielRF* - Bot used to track packages on the Brazilian Mail Service.
|
||||
* [filex_bot](http://t.me/filex_bot)([link](https://github.com/victor141516/FileXbot-telegram))
|
||||
* [Spbu4UBot](http://t.me/Spbu4UBot)([link](https://github.com/EeOneDown/spbu4u)) by *EeOneDown* - Bot with timetables for SPbU students.
|
||||
* [SmartySBot](http://t.me/ZDU_bot)([link](https://github.com/0xVK/SmartySBot)) by *0xVK* - Telegram timetable bot, for Zhytomyr Ivan Franko State University students.
|
||||
* [yandex_music_bot](http://t.me/yandex_music_bot)- Downloads tracks/albums/public playlists from Yandex.Music streaming service for free.
|
||||
* [LearnIt](https://t.me/LearnItbot)([link](https://github.com/tiagonapoli/LearnIt)) - A Telegram Bot created to help people to memorize other languages’ vocabulary.
|
||||
* [MusicQuiz_bot](https://t.me/MusicQuiz_bot) by [Etoneja](https://github.com/Etoneja) - Listen to audiosamles and try to name the performer of the song.
|
||||
* [Bot-Telegram-Shodan ](https://github.com/rubenleon/Bot-Telegram-Shodan) by [rubenleon](https://github.com/rubenleon)
|
||||
* [MandangoBot](https://t.me/MandangoBot) by @Alvaricias - Bot for managing Marvel Strike Force alliances (only in spanish, atm).
|
||||
* [ManjaroBot](https://t.me/ManjaroBot) by [@NeoRanger](https://github.com/neoranger) - Bot for Manjaro Linux Spanish group with a lot of info for Manjaro Newbies.
|
||||
* [VigoBusTelegramBot](https://t.me/vigobusbot) ([GitHub](https://github.com/Pythoneiro/VigoBus-TelegramBot)) - Bot that provides buses coming to a certain stop and their remaining time for the city of Vigo (Galicia - Spain)
|
||||
* [kaishnik-bot](https://t.me/kaishnik_bot) ([source](https://github.com/airatk/kaishnik-bot)) by *airatk* - bot which shows all the necessary information to KNTRU-KAI students.
|
||||
* [Creation Date](https://t.me/creationdatebot) by @karipov - interpolates account creation dates based on telegram given ID’s
|
||||
* [m0xbot](https://t.me/m0xbot) by [kor0p](https://github.com/kor0p) - tic-tac-toe.
|
||||
* [kboardbot](https://t.me/kboardbot) by [kor0p](https://github.com/kor0p) - inline switches keyboard layout (English, Hebrew, Ukrainian, Russian).
|
||||
* [Robbie](https://t.me/romdeliverybot) ([source](https://github.com/FacuM/romdeliverybot_support)) by @FacuM - Support Telegram bot for developers and maintainers.
|
||||
* [AsadovBot](https://t.me/asadov_bot) ([source](https://github.com/desexcile/BotApi)) by @DesExcile - Сatalog of poems by Eduard Asadov.
|
||||
* [thesaurus_com_bot](https://t.me/thesaurus_com_bot) ([source](https://github.com/LeoSvalov/words-i-learn-bot)) by @LeoSvalov - words and synonyms from [dictionary.com](https://www.dictionary.com) and [thesaurus.com](https://www.thesaurus.com) in the telegram.
|
||||
|
||||
Want to have your bot listed here? Send a Telegram message to @eternnoir or @pevdh.
|
||||
|
807
README.rst
807
README.rst
@ -1,807 +0,0 @@
|
||||
#
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<p align="center">
|
||||
|
||||
pyTelegramBotAPI
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<p align="center">
|
||||
|
||||
A simple, but extensible Python implementation for the `Telegram Bot
|
||||
API <https://core.telegram.org/bots/api>`__.
|
||||
|
||||
|Download Month| |Build Status| |Download Month|
|
||||
|
||||
- `Getting started. <#getting-started>`__
|
||||
- `Writing your first bot <#writing-your-first-bot>`__
|
||||
|
||||
- `Prerequisites <#prerequisites>`__
|
||||
- `A simple echo bot <#a-simple-echo-bot>`__
|
||||
|
||||
- `General API Documentation <#general-api-documentation>`__
|
||||
|
||||
- `Types <#types>`__
|
||||
- `Methods <#methods>`__
|
||||
- `General use of the API <#general-use-of-the-api>`__
|
||||
- `Message handlers <#message-handlers>`__
|
||||
- `Callback Query handlers <#callback-query-handler>`__
|
||||
- `TeleBot <#telebot>`__
|
||||
- `Reply markup <#reply-markup>`__
|
||||
- `Inline Mode <#inline-mode>`__
|
||||
|
||||
- `Advanced use of the API <#advanced-use-of-the-api>`__
|
||||
|
||||
- `Asynchronous delivery of
|
||||
messages <#asynchronous-delivery-of-messages>`__
|
||||
- `Sending large text messages <#sending-large-text-messages>`__
|
||||
- `Controlling the amount of Threads used by
|
||||
TeleBot <#controlling-the-amount-of-threads-used-by-telebot>`__
|
||||
- `The listener mechanism <#the-listener-mechanism>`__
|
||||
- `Using web hooks <#using-web-hooks>`__
|
||||
- `Logging <#logging>`__
|
||||
|
||||
- `F.A.Q. <#faq>`__
|
||||
|
||||
- `Bot 2.0 <#bot-20>`__
|
||||
- `How can I distinguish a User and a GroupChat in
|
||||
message.chat? <#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat>`__
|
||||
|
||||
- `The Telegram Chat Group <#the-telegram-chat-group>`__
|
||||
- `More examples <#more-examples>`__
|
||||
- `Bots using this API <#bots-using-this-api>`__
|
||||
|
||||
Getting started.
|
||||
----------------
|
||||
|
||||
This API is tested with Python 2.6, Python 2.7, Python 3.4, Pypy and
|
||||
Pypy 3. There are two ways to install the library:
|
||||
|
||||
- Installation using pip (a Python package manager)\*:
|
||||
|
||||
::
|
||||
|
||||
$ pip install pyTelegramBotAPI
|
||||
|
||||
- Installation from source (requires git):
|
||||
|
||||
::
|
||||
|
||||
$ git clone https://github.com/eternnoir/pyTelegramBotAPI.git
|
||||
$ cd pyTelegramBotAPI
|
||||
$ python setup.py install
|
||||
|
||||
It is generally recommended to use the first option.
|
||||
|
||||
\*\*While the API is production-ready, it is still under development and
|
||||
it has regular updates, do not forget to update it regularly by calling
|
||||
``pip install pytelegrambotapi --upgrade``\ \*
|
||||
|
||||
Writing your first bot
|
||||
----------------------
|
||||
|
||||
Prerequisites
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
It is presumed that you [have obtained an API token with
|
||||
@BotFather](https://core.telegram.org/bots#botfather). We will call this
|
||||
token ``TOKEN``. Furthermore, you have basic knowledge of the Python
|
||||
programming language and more importantly `the Telegram Bot
|
||||
API <https://core.telegram.org/bots/api>`__.
|
||||
|
||||
A simple echo bot
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The TeleBot class (defined in \_\_init\_\_.py) encapsulates all API
|
||||
calls in a single class. It provides functions such as ``send_xyz``
|
||||
(``send_message``, ``send_document`` etc.) and several ways to listen
|
||||
for incoming messages.
|
||||
|
||||
Create a file called ``echo_bot.py``. Then, open the file and create an
|
||||
instance of the TeleBot class.
|
||||
|
||||
.. code:: python
|
||||
|
||||
import telebot
|
||||
|
||||
bot = telebot.TeleBot("TOKEN")
|
||||
|
||||
*Note: Make sure to actually replace TOKEN with your own API token.*
|
||||
|
||||
After that declaration, we need to register some so-called message
|
||||
handlers. Message handlers define filters which a message must pass. If
|
||||
a message passes the filter, the decorated function is called and the
|
||||
incoming message is passed as an argument.
|
||||
|
||||
Let's define a message handler which handles incoming ``/start`` and
|
||||
``/help`` commands.
|
||||
|
||||
.. code:: python
|
||||
|
||||
@bot.message_handler(commands=['start', 'help'])
|
||||
def send_welcome(message):
|
||||
bot.reply_to(message, "Howdy, how are you doing?")
|
||||
|
||||
A function which is decorated by a message handler **can have an
|
||||
arbitrary name, however, it must have only one parameter (the
|
||||
message)**.
|
||||
|
||||
Let's add another handler:
|
||||
|
||||
.. code:: python
|
||||
|
||||
@bot.message_handler(func=lambda m: True)
|
||||
def echo_all(message):
|
||||
bot.reply_to(message, message.text)
|
||||
|
||||
This one echoes all incoming text messages back to the sender. It uses a
|
||||
lambda function to test a message. If the lambda returns True, the
|
||||
message is handled by the decorated function. Since we want all messages
|
||||
to be handled by this function, we simply always return True.
|
||||
|
||||
*Note: all handlers are tested in the order in which they were declared*
|
||||
|
||||
We now have a basic bot which replies a static message to "/start" and
|
||||
"/help" commands and which echoes the rest of the sent messages. To
|
||||
start the bot, add the following to our source file:
|
||||
|
||||
.. code:: python
|
||||
|
||||
bot.polling()
|
||||
|
||||
Alright, that's it! Our source file now looks like this:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import telebot
|
||||
|
||||
bot = telebot.TeleBot("TOKEN")
|
||||
|
||||
@bot.message_handler(commands=['start', 'help'])
|
||||
def send_welcome(message):
|
||||
bot.reply_to(message, "Howdy, how are you doing?")
|
||||
|
||||
@bot.message_handler(func=lambda message: True)
|
||||
def echo_all(message):
|
||||
bot.reply_to(message, message.text)
|
||||
|
||||
bot.polling()
|
||||
|
||||
To start the bot, simply open up a terminal and enter
|
||||
``python echo_bot.py`` to run the bot! Test it by sending commands
|
||||
('/start' and '/help') and arbitrary text messages.
|
||||
|
||||
General API Documentation
|
||||
-------------------------
|
||||
|
||||
Types
|
||||
~~~~~
|
||||
|
||||
All types are defined in types.py. They are all completely in line with
|
||||
the `Telegram API's definition of the
|
||||
types <https://core.telegram.org/bots/api#available-types>`__, except
|
||||
for the Message's ``from`` field, which is renamed to ``from_user``
|
||||
(because ``from`` is a Python reserved token). Thus, attributes such as
|
||||
``message_id`` can be accessed directly with ``message.message_id``.
|
||||
Note that ``message.chat`` can be either an instance of ``User`` or
|
||||
``GroupChat`` (see `How can I distinguish a User and a GroupChat in
|
||||
message.chat? <#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat>`__).
|
||||
|
||||
The Message object also has a ``content_types``\ attribute, which
|
||||
defines the type of the Message. ``content_types`` can be one of the
|
||||
following strings: 'text', 'audio', 'document', 'photo', 'sticker',
|
||||
'video', 'voice', 'location', 'contact', 'new\_chat\_participant',
|
||||
'left\_chat\_participant', 'new\_chat\_title', 'new\_chat\_photo',
|
||||
'delete\_chat\_photo', 'group\_chat\_created'.
|
||||
|
||||
Methods
|
||||
~~~~~~~
|
||||
|
||||
All `API
|
||||
methods <https://core.telegram.org/bots/api#available-methods>`__ are
|
||||
located in the TeleBot class. They are renamed to follow common Python
|
||||
naming conventions. E.g. ``getMe`` is renamed to ``get_me`` and
|
||||
``sendMessage`` to ``send_message``.
|
||||
|
||||
General use of the API
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Outlined below are some general use cases of the API.
|
||||
|
||||
Message handlers
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
A message handler is a function that is decorated with the
|
||||
``message_handler`` decorator of a TeleBot instance. Message handlers
|
||||
consist of one or multiple filters. Each filter much return True for a
|
||||
certain message in order for a message handler to become eligible to
|
||||
handle that message. A message handler is declared in the following way
|
||||
(provided ``bot`` is an instance of TeleBot):
|
||||
|
||||
.. code:: python
|
||||
|
||||
@bot.message_handler(filters)
|
||||
def function_name(message):
|
||||
bot.reply_to(message, "This is a message handler")
|
||||
|
||||
``function_name`` is not bound to any restrictions. Any function name is
|
||||
permitted with message handlers. The function must accept at most one
|
||||
argument, which will be the message that the function must handle.
|
||||
``filters`` is a list of keyword arguments. A filter is declared in the
|
||||
following manner: ``name=argument``. One handler may have multiple
|
||||
filters. TeleBot supports the following filters:
|
||||
|
||||
+--------+------+------+
|
||||
| name | argu | Cond |
|
||||
| | ment | itio |
|
||||
| | (s) | n |
|
||||
+========+======+======+
|
||||
| conten | list | ``Tr |
|
||||
| t\_typ | of | ue`` |
|
||||
| es | stri | if |
|
||||
| | ngs | mess |
|
||||
| | (def | age. |
|
||||
| | ault | cont |
|
||||
| | ``[' | ent\ |
|
||||
| | text | _typ |
|
||||
| | ']`` | e |
|
||||
| | ) | is |
|
||||
| | | in |
|
||||
| | | the |
|
||||
| | | list |
|
||||
| | | of |
|
||||
| | | stri |
|
||||
| | | ngs. |
|
||||
+--------+------+------+
|
||||
| regexp | a | ``Tr |
|
||||
| | regu | ue`` |
|
||||
| | lar | if |
|
||||
| | expr | ``re |
|
||||
| | essi | .sea |
|
||||
| | on | rch( |
|
||||
| | as a | rege |
|
||||
| | stri | xp_a |
|
||||
| | ng | rg)` |
|
||||
| | | ` |
|
||||
| | | retu |
|
||||
| | | rns |
|
||||
| | | ``Tr |
|
||||
| | | ue`` |
|
||||
| | | and |
|
||||
| | | ``me |
|
||||
| | | ssag |
|
||||
| | | e.co |
|
||||
| | | nten |
|
||||
| | | t_ty |
|
||||
| | | pe = |
|
||||
| | | = 't |
|
||||
| | | ext' |
|
||||
| | | `` |
|
||||
| | | (See |
|
||||
| | | `Pyt |
|
||||
| | | hon |
|
||||
| | | Regu |
|
||||
| | | lar |
|
||||
| | | Expr |
|
||||
| | | essi |
|
||||
| | | ons |
|
||||
| | | <htt |
|
||||
| | | ps:/ |
|
||||
| | | /doc |
|
||||
| | | s.py |
|
||||
| | | thon |
|
||||
| | | .org |
|
||||
| | | /2/l |
|
||||
| | | ibra |
|
||||
| | | ry/r |
|
||||
| | | e.ht |
|
||||
| | | ml>` |
|
||||
| | | __ |
|
||||
+--------+------+------+
|
||||
| comman | list | ``Tr |
|
||||
| ds | of | ue`` |
|
||||
| | stri | if |
|
||||
| | ngs | ``me |
|
||||
| | | ssag |
|
||||
| | | e.co |
|
||||
| | | nten |
|
||||
| | | t_ty |
|
||||
| | | pe = |
|
||||
| | | = 't |
|
||||
| | | ext' |
|
||||
| | | `` |
|
||||
| | | and |
|
||||
| | | ``me |
|
||||
| | | ssag |
|
||||
| | | e.te |
|
||||
| | | xt`` |
|
||||
| | | star |
|
||||
| | | ts |
|
||||
| | | with |
|
||||
| | | a |
|
||||
| | | comm |
|
||||
| | | and |
|
||||
| | | that |
|
||||
| | | is |
|
||||
| | | in |
|
||||
| | | the |
|
||||
| | | list |
|
||||
| | | of |
|
||||
| | | stri |
|
||||
| | | ngs. |
|
||||
+--------+------+------+
|
||||
| func | a | ``Tr |
|
||||
| | func | ue`` |
|
||||
| | tion | if |
|
||||
| | (lam | the |
|
||||
| | bda | lamb |
|
||||
| | or | da |
|
||||
| | func | or |
|
||||
| | tion | func |
|
||||
| | refe | tion |
|
||||
| | renc | refe |
|
||||
| | e) | renc |
|
||||
| | | e |
|
||||
| | | retu |
|
||||
| | | rns |
|
||||
| | | ``Tr |
|
||||
| | | ue`` |
|
||||
+--------+------+------+
|
||||
|
||||
Here are some examples of using the filters and message handlers:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import telebot
|
||||
bot = telebot.TeleBot("TOKEN")
|
||||
|
||||
# Handles all text messages that contains the commands '/start' or '/help'.
|
||||
@bot.message_handler(commands=['start', 'help'])
|
||||
def handle_start_help(message):
|
||||
pass
|
||||
|
||||
# Handles all sent documents and audio files
|
||||
@bot.message_handler(content_types=['document', 'audio'])
|
||||
def handle_docs_audio(message):
|
||||
pass
|
||||
|
||||
# Handles all text messages that match the regular expression
|
||||
@bot.message_handler(regexp="SOME_REGEXP")
|
||||
def handle_message(message):
|
||||
pass
|
||||
|
||||
#Handles all messages for which the lambda returns True
|
||||
@bot.message_handler(func=lambda message: message.document.mime_type == 'text/plain', content_types=['document'])
|
||||
def handle_text_doc(message):
|
||||
pass
|
||||
|
||||
#Which could also be defined as:
|
||||
def test_message(message):
|
||||
return message.document.mime_type == 'text/plan'
|
||||
|
||||
@bot.message_handler(func=test_message, content_types=['document'])
|
||||
def handle_text_doc(message)
|
||||
pass
|
||||
|
||||
# Handlers can be stacked to create a function which will be called if either message_handler is eligible
|
||||
# This handler will be called if the message starts with '/hello' OR is some emoji
|
||||
@bot.message_handler(commands=['hello'])
|
||||
@bot.message_handler(func=lambda msg: msg.text.encode("utf-8") == SOME_FANCY_EMOJI)
|
||||
def send_something(message):
|
||||
pass
|
||||
|
||||
**Important: all handlers are tested in the order in which they were
|
||||
declared**
|
||||
|
||||
Callback Query Handler
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In bot2.0 update. You can get ``callback_query`` in update object. In
|
||||
telebot use ``callback_query_handler`` to process callback\_querys.
|
||||
|
||||
.. code:: python
|
||||
|
||||
@bot.callback_query_handler(func=lambda call: True)
|
||||
def test_callback(call):
|
||||
logger.info(call)
|
||||
|
||||
TeleBot
|
||||
^^^^^^^
|
||||
|
||||
.. code:: python
|
||||
|
||||
import telebot
|
||||
|
||||
TOKEN = '<token_string>'
|
||||
tb = telebot.TeleBot(TOKEN) #create a new Telegram Bot object
|
||||
|
||||
# Upon calling this function, TeleBot starts polling the Telegram servers for new messages.
|
||||
# - none_stop: True/False (default False) - Don't stop polling when receiving an error from the Telegram servers
|
||||
# - interval: True/False (default False) - The interval between polling requests
|
||||
# Note: Editing this parameter harms the bot's response time
|
||||
# - timeout: integer (default 20) - Timeout in seconds for long polling.
|
||||
tb.polling(none_stop=False, interval=0, timeout=20)
|
||||
|
||||
# getMe
|
||||
user = tb.get_me()
|
||||
|
||||
# setWebhook
|
||||
tb.set_webhook(url="http://example.com", certificate=open('mycert.pem'))
|
||||
# unset webhook
|
||||
tb.remove_webhook()
|
||||
|
||||
# getUpdates
|
||||
updates = tb.get_updates()
|
||||
updates = tb.get_updates(1234,100,20) #get_Updates(offset, limit, timeout):
|
||||
|
||||
# sendMessage
|
||||
tb.send_message(chatid, text)
|
||||
|
||||
# forwardMessage
|
||||
tb.forward_message(to_chat_id, from_chat_id, message_id)
|
||||
|
||||
# All send_xyz functions which can take a file as an argument, can also take a file_id instead of a file.
|
||||
# sendPhoto
|
||||
photo = open('/tmp/photo.png', 'rb')
|
||||
tb.send_photo(chat_id, photo)
|
||||
tb.send_photo(chat_id, "FILEID")
|
||||
|
||||
# sendAudio
|
||||
audio = open('/tmp/audio.mp3', 'rb')
|
||||
tb.send_audio(chat_id, audio)
|
||||
tb.send_audio(chat_id, "FILEID")
|
||||
|
||||
## sendAudio with duration, performer and title.
|
||||
tb.send_audio(CHAT_ID, file_data, 1, 'eternnoir', 'pyTelegram')
|
||||
|
||||
# sendVoice
|
||||
voice = open('/tmp/voice.ogg', 'rb')
|
||||
tb.send_voice(chat_id, voice)
|
||||
tb.send_voice(chat_id, "FILEID")
|
||||
|
||||
# sendDocument
|
||||
doc = open('/tmp/file.txt', 'rb')
|
||||
tb.send_document(chat_id, doc)
|
||||
tb.send_document(chat_id, "FILEID")
|
||||
|
||||
# sendSticker
|
||||
sti = open('/tmp/sti.webp', 'rb')
|
||||
tb.send_sticker(chat_id, sti)
|
||||
tb.send_sticker(chat_id, "FILEID")
|
||||
|
||||
# sendVideo
|
||||
video = open('/tmp/video.mp4', 'rb')
|
||||
tb.send_video(chat_id, video)
|
||||
tb.send_video(chat_id, "FILEID")
|
||||
|
||||
# sendLocation
|
||||
tb.send_location(chat_id, lat, lon)
|
||||
|
||||
# sendChatAction
|
||||
# action_string can be one of the following strings: 'typing', 'upload_photo', 'record_video', 'upload_video',
|
||||
# 'record_audio', 'upload_audio', 'upload_document' or 'find_location'.
|
||||
tb.send_chat_action(chat_id, action_string)
|
||||
|
||||
# getFile
|
||||
# Downloading a file is straightforward
|
||||
# Returns a File object
|
||||
import requests
|
||||
file_info = tb.get_file(file_id)
|
||||
|
||||
file = requests.get('https://api.telegram.org/file/bot{0}/{1}'.format(API_TOKEN, file_info.file_path))
|
||||
|
||||
Reply markup
|
||||
^^^^^^^^^^^^
|
||||
|
||||
All ``send_xyz`` functions of TeleBot take an optional ``reply_markup``
|
||||
argument. This argument must be an instance of ``ReplyKeyboardMarkup``,
|
||||
``ReplyKeyboardRemove`` or ``ForceReply``, which are defined in types.py.
|
||||
|
||||
.. code:: python
|
||||
|
||||
from telebot import types
|
||||
|
||||
# Using the ReplyKeyboardMarkup class
|
||||
# It's constructor can take the following optional arguments:
|
||||
# - resize_keyboard: True/False (default False)
|
||||
# - one_time_keyboard: True/False (default False)
|
||||
# - selective: True/False (default False)
|
||||
# - row_width: integer (default 3)
|
||||
# row_width is used in combination with the add() function.
|
||||
# It defines how many buttons are fit on each row before continuing on the next row.
|
||||
markup = types.ReplyKeyboardMarkup(row_width=2)
|
||||
itembtn1 = types.KeyboardButton('a')
|
||||
itembtn2 = types.KeyboardButton('v')
|
||||
itembtn3 = types.KeyboardButton('d')
|
||||
markup.add(itembtn1, itembtn2, itembtn3)
|
||||
tb.send_message(chat_id, "Choose one letter:", reply_markup=markup)
|
||||
|
||||
# or add strings one row at a time:
|
||||
markup = types.ReplyKeyboardMarkup()
|
||||
itembtna = types.KeyboardButton('a')
|
||||
itembtnv = types.KeyboardButton('v')
|
||||
itembtnc = types.KeyboardButton('c')
|
||||
itembtnd = types.KeyboardButton('d')
|
||||
itembtne = types.KeyboardButton('e')
|
||||
markup.row(itembtna, itembtnv)
|
||||
markup.row(itembtnc, itembtnd, itembtne)
|
||||
tb.send_message(chat_id, "Choose one letter:", reply_markup=markup)
|
||||
|
||||
The last example yields this result:
|
||||
|
||||
.. figure:: https://pp.vk.me/c624430/v624430512/473e5/_mxxW7FPe4U.jpg
|
||||
:alt: ReplyKeyboardMarkup
|
||||
|
||||
ReplyKeyboardMarkup
|
||||
|
||||
.. code:: python
|
||||
|
||||
# ReplyKeyboardRemove: hides a previously sent ReplyKeyboardMarkup
|
||||
# Takes an optional selective argument (True/False, default False)
|
||||
markup = types.ReplyKeyboardRemove(selective=False)
|
||||
tb.send_message(chat_id, message, reply_markup=markup)
|
||||
|
||||
.. code:: python
|
||||
|
||||
# ForceReply: forces a user to reply to a message
|
||||
# Takes an optional selective argument (True/False, default False)
|
||||
markup = types.ForceReply(selective=False)
|
||||
tb.send_message(chat_id, "Send me another word:", reply_markup=markup)
|
||||
|
||||
ForceReply:
|
||||
|
||||
.. figure:: https://pp.vk.me/c624430/v624430512/473ec/602byyWUHcs.jpg
|
||||
:alt: ForceReply
|
||||
|
||||
ForceReply
|
||||
|
||||
Inline Mode
|
||||
~~~~~~~~~~~
|
||||
|
||||
More information about `Inline
|
||||
mode <https://core.telegram.org/bots/inline>`__.
|
||||
|
||||
inline\_handler
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Now, you can use inline\_handler to get inline\_query in telebot.
|
||||
|
||||
.. code:: python
|
||||
|
||||
|
||||
@bot.inline_handler(lambda query: query.query == 'text')
|
||||
def query_text(inline_query):
|
||||
# Query message is text
|
||||
|
||||
chosen\_inline\_handler
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use chosen\_inline\_handler to get chosen\_inline\_result in telebot.
|
||||
Don't forgot add the /setinlinefeedback command for @Botfather.
|
||||
|
||||
More information :
|
||||
`collecting-feedback <https://core.telegram.org/bots/inline#collecting-feedback>`__
|
||||
|
||||
.. code:: python
|
||||
|
||||
@bot.chosen_inline_handler(func=lambda chosen_inline_result: True)
|
||||
def test_chosen(chosen_inline_result):
|
||||
# Process all chosen_inline_result.
|
||||
|
||||
answer\_inline\_query
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code:: python
|
||||
|
||||
@bot.inline_handler(lambda query: query.query == 'text')
|
||||
def query_text(inline_query):
|
||||
try:
|
||||
r = types.InlineQueryResultArticle('1', 'Result', 'Result message.')
|
||||
r2 = types.InlineQueryResultArticle('2', 'Result2', 'Result message2.')
|
||||
bot.answer_inline_query(inline_query.id, [r, r2])
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
Advanced use of the API
|
||||
-----------------------
|
||||
|
||||
Asynchronous delivery of messages
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There exists an implementation of TeleBot which executes all
|
||||
``send_xyz`` and the ``get_me`` functions asynchronously. This can speed
|
||||
up you bot **significantly**, but it has unwanted side effects if used
|
||||
without caution. To enable this behaviour, create an instance of
|
||||
AsyncTeleBot instead of TeleBot.
|
||||
|
||||
.. code:: python
|
||||
|
||||
tb = telebot.AsyncTeleBot("TOKEN")
|
||||
|
||||
Now, every function that calls the Telegram API is executed in a
|
||||
separate Thread. The functions are modified to return an AsyncTask
|
||||
instance (defined in util.py). Using AsyncTeleBot allows you to do the
|
||||
following:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import telebot
|
||||
|
||||
tb = telebot.AsyncTeleBot("TOKEN")
|
||||
task = tb.get_me() # Execute an API call
|
||||
# Do some other operations...
|
||||
a = 0
|
||||
for a in range(100):
|
||||
a += 10
|
||||
|
||||
result = task.wait() # Get the result of the execution
|
||||
|
||||
*Note: if you execute send\_xyz functions after eachother without
|
||||
calling wait(), the order in which messages are delivered might be
|
||||
wrong.*
|
||||
|
||||
Sending large text messages
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sometimes you must send messages that exceed 5000 characters. The
|
||||
Telegram API can not handle that many characters in one request, so we
|
||||
need to split the message in multiples. Here is how to do that using the
|
||||
API:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from telebot import util
|
||||
large_text = open("large_text.txt", "rb").read()
|
||||
|
||||
# Split the text each 3000 characters.
|
||||
# split_string returns a list with the splitted text.
|
||||
splitted_text = util.split_string(large_text, 3000)
|
||||
for text in splitted_text:
|
||||
tb.send_message(chat_id, text)
|
||||
|
||||
Controlling the amount of Threads used by TeleBot
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The TeleBot constructor takes the following optional arguments:
|
||||
|
||||
- create\_threads: True/False (default True). A flag to indicate
|
||||
whether TeleBot should execute message handlers on it's polling
|
||||
Thread.
|
||||
- num\_threads: integer (default 4). Controls the amount of
|
||||
WorkerThreads created for the internal thread pool that TeleBot uses
|
||||
to execute message handlers. Is not used when create\_threads is
|
||||
False.
|
||||
|
||||
The listener mechanism
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
As an alternative to the message handlers, one can also register a
|
||||
function as a listener to TeleBot. Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
def handle_messages(messages):
|
||||
for message in messsages:
|
||||
# Do something with the message
|
||||
bot.reply_to(message, 'Hi')
|
||||
|
||||
bot.set_update_listener(handle_messages)
|
||||
bot.polling()
|
||||
|
||||
Using webhooks
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
When using webhooks telegram sends one Update per call, for processing
|
||||
it you should call process\_new\_messages([update.message]) when you
|
||||
recieve it.
|
||||
|
||||
There are some examples using webhooks in the
|
||||
*examples/webhook\_examples* directory.
|
||||
|
||||
Logging
|
||||
~~~~~~~
|
||||
|
||||
You can use the Telebot module logger to log debug info about Telebot.
|
||||
Use ``telebot.logger`` to get the logger of the TeleBot module. It is
|
||||
possible to add custom logging Handlers to the logger. Refer to the
|
||||
`Python logging module
|
||||
page <https://docs.python.org/2/library/logging.html>`__ for more info.
|
||||
|
||||
.. code:: python
|
||||
|
||||
import logging
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console.
|
||||
|
||||
F.A.Q.
|
||||
------
|
||||
|
||||
Bot 2.0
|
||||
~~~~~~~
|
||||
|
||||
April 9,2016 Telegram release new bot 2.0 API, which has a drastic
|
||||
revision especially for the change of method's interface.If you want to
|
||||
update to the latest version, please make sure you've switched bot's
|
||||
code to bot 2.0 method interface.
|
||||
|
||||
`More information about pyTelegramBotAPI support
|
||||
bot2.0 <https://github.com/eternnoir/pyTelegramBotAPI/issues/130>`__
|
||||
|
||||
How can I distinguish a User and a GroupChat in message.chat?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Telegram Bot API support new type Chat for message.chat.
|
||||
|
||||
- Check the ``type`` attribute in ``Chat`` object:
|
||||
- \`\`\`python if message.chat.type == “private”: # private chat
|
||||
message
|
||||
|
||||
if message.chat.type == “group”: # group chat message
|
||||
|
||||
if message.chat.type == “supergroup”: # supergroup chat message
|
||||
|
||||
if message.chat.type == “channel”: # channel message
|
||||
|
||||
\`\`\`
|
||||
|
||||
The Telegram Chat Group
|
||||
-----------------------
|
||||
|
||||
Get help. Discuss. Chat.
|
||||
|
||||
- Join the pyTelegramBotAPI Telegram Chat Group
|
||||
- Messge to @eternnoir by telegram for Invitation.
|
||||
- We now have a Telegram Channel as well! Keep yourself up to date with
|
||||
API changes, and `join it <https://telegram.me/pytelegrambotapi>`__.
|
||||
|
||||
More examples
|
||||
-------------
|
||||
|
||||
- `Echo
|
||||
Bot <https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/echo_bot.py>`__
|
||||
- `Deep
|
||||
Linking <https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/deep_linking.py>`__
|
||||
- `next\_step\_handler
|
||||
Example <https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/step_example.py>`__
|
||||
|
||||
Bots using this API
|
||||
-------------------
|
||||
|
||||
- `SiteAlert bot <https://telegram.me/SiteAlert_bot>`__
|
||||
(`source <https://github.com/ilteoood/SiteAlert-Python>`__) by
|
||||
*ilteoood* - Monitors websites and sends a notification on changes
|
||||
- `TelegramLoggingBot <https://github.com/aRandomStranger/TelegramLoggingBot>`__
|
||||
by *aRandomStranger*
|
||||
- `Telegram
|
||||
LMGTFY\_bot <https://github.com/GabrielRF/telegram-lmgtfy_bot>`__ by
|
||||
*GabrielRF*
|
||||
- `Telegram
|
||||
UrlProBot <https://github.com/GabrielRF/telegram-urlprobot>`__ by
|
||||
*GabrielRF*
|
||||
- `Telegram Proxy
|
||||
Bot <https://bitbucket.org/master_groosha/telegram-proxy-bot>`__ by
|
||||
*Groosha* - A simple BITM (bot-in-the-middle) for Telegram acting as
|
||||
some kind of "proxy".
|
||||
- `Telegram Proxy Bot <https://github.com/mrgigabyte/proxybot>`__ by
|
||||
*mrgigabyte* -
|
||||
``Credits for the original version of this bot goes to`` **Groosha**
|
||||
``, simply added certain features which I thought were needed``.
|
||||
- `RadRetroRobot <https://github.com/Tronikart/RadRetroRobot>`__ by
|
||||
*Tronikart* - Multifunctional Telegram Bot RadRetroRobot.
|
||||
- `League of Legends bot <https://telegram.me/League_of_Legends_bot>`__
|
||||
(`source <https://github.com/i32ropie/lol>`__) by *i32ropie*
|
||||
- `NeoBot <https://github.com/neoranger/NeoBot>`__ by *neoranger*
|
||||
- `TagAlertBot <https://github.com/pitasi/TagAlertBot>`__ by *pitasi*
|
||||
|
||||
Want to have your bot listed here? Send a Telegram message to @eternnoir
|
||||
or @pevdh.
|
||||
|
||||
.. |Download Month| image:: https://img.shields.io/pypi/v/pyTelegramBotAPI.svg
|
||||
:target: https://pypi.python.org/pypi/pyTelegramBotAPI
|
||||
.. |Build Status| image:: https://travis-ci.org/eternnoir/pyTelegramBotAPI.svg?branch=master
|
||||
:target: https://travis-ci.org/eternnoir/pyTelegramBotAPI
|
||||
.. |Download Month| image:: https://img.shields.io/pypi/dm/pyTelegramBotAPI.svg
|
||||
:target: https://pypi.python.org/pypi/pyTelegramBotAPI
|
@ -1,3 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# This example shows how to implement deep linking (https://core.telegram.org/bots#deep-linking)
|
||||
# with the pyTelegramBotAPI.
|
||||
# Note: This is not a working, production-ready sample.
|
||||
@ -31,34 +33,38 @@
|
||||
# steps are not shown here. Only steps 5 to 7 are illustrated, some in pseudo-code, with this example.
|
||||
|
||||
import telebot
|
||||
import time
|
||||
|
||||
bot = telebot.TeleBot('TOKEN')
|
||||
|
||||
|
||||
def extract_unique_code(text):
|
||||
# Extracts the unique_code from the sent /start command.
|
||||
return text.split()[1] if len(text.split()) > 1 else None
|
||||
|
||||
|
||||
def in_storage(unique_code):
|
||||
# (pseudo-code) Should check if a unique code exists in storage
|
||||
return True
|
||||
|
||||
|
||||
def get_username_from_storage(unique_code):
|
||||
# (pseudo-code) Does a query to the storage, retrieving the associated username
|
||||
# Should be replaced by a real database-lookup.
|
||||
return "ABC" if in_storage(unique_code) else None
|
||||
|
||||
|
||||
def save_chat_id(chat_id, username):
|
||||
# (pseudo-code) Save the chat_id->username to storage
|
||||
# Should be replaced by a real database query.
|
||||
pass
|
||||
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
def send_welcome(message):
|
||||
unique_code = extract_unique_code(message.text)
|
||||
if unique_code: # if the '/start' command contains a unique_code
|
||||
if unique_code: # if the '/start' command contains a unique_code
|
||||
username = get_username_from_storage(unique_code)
|
||||
if username: # if the username exists in our database
|
||||
if username: # if the username exists in our database
|
||||
save_chat_id(message.chat.id, username)
|
||||
reply = "Hello {0}, how are you?".format(username)
|
||||
else:
|
||||
@ -67,4 +73,5 @@ def send_welcome(message):
|
||||
reply = "Please visit me via a provided URL from the website."
|
||||
bot.reply_to(message, reply)
|
||||
|
||||
|
||||
bot.polling()
|
||||
|
@ -2,9 +2,10 @@
|
||||
This is a detailed example using almost every command of the API
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
import telebot
|
||||
from telebot import types
|
||||
import time
|
||||
|
||||
TOKEN = '<token_string>'
|
||||
|
||||
@ -12,14 +13,14 @@ knownUsers = [] # todo: save these in a file,
|
||||
userStep = {} # so they won't reset every time the bot restarts
|
||||
|
||||
commands = { # command description used in the "help" command
|
||||
'start': 'Get used to the bot',
|
||||
'help': 'Gives you information about the available commands',
|
||||
'sendLongText': 'A test using the \'send_chat_action\' command',
|
||||
'getImage': 'A test using multi-stage messages, custom keyboard, and media sending'
|
||||
'start' : 'Get used to the bot',
|
||||
'help' : 'Gives you information about the available commands',
|
||||
'sendLongText': 'A test using the \'send_chat_action\' command',
|
||||
'getImage' : 'A test using multi-stage messages, custom keyboard, and media sending'
|
||||
}
|
||||
|
||||
imageSelect = types.ReplyKeyboardMarkup(one_time_keyboard=True) # create the image selection keyboard
|
||||
imageSelect.add('cock', 'pussy')
|
||||
imageSelect.add('Mickey', 'Minnie')
|
||||
|
||||
hideBoard = types.ReplyKeyboardRemove() # if sent as reply_markup, will hide the keyboard
|
||||
|
||||
@ -33,7 +34,7 @@ def get_user_step(uid):
|
||||
else:
|
||||
knownUsers.append(uid)
|
||||
userStep[uid] = 0
|
||||
print "New user detected, who hasn't used \"/start\" yet"
|
||||
print("New user detected, who hasn't used \"/start\" yet")
|
||||
return 0
|
||||
|
||||
|
||||
@ -45,7 +46,7 @@ def listener(messages):
|
||||
for m in messages:
|
||||
if m.content_type == 'text':
|
||||
# print the sent message to the console
|
||||
print str(m.chat.first_name) + " [" + str(m.chat.id) + "]: " + m.text
|
||||
print(str(m.chat.first_name) + " [" + str(m.chat.id) + "]: " + m.text)
|
||||
|
||||
|
||||
bot = telebot.TeleBot(TOKEN)
|
||||
@ -104,15 +105,15 @@ def msg_image_select(m):
|
||||
# for some reason the 'upload_photo' status isn't quite working (doesn't show at all)
|
||||
bot.send_chat_action(cid, 'typing')
|
||||
|
||||
if text == "cock": # send the appropriate image based on the reply to the "/getImage" command
|
||||
if text == 'Mickey': # send the appropriate image based on the reply to the "/getImage" command
|
||||
bot.send_photo(cid, open('rooster.jpg', 'rb'),
|
||||
reply_markup=hideBoard) # send file and hide keyboard, after image is sent
|
||||
userStep[cid] = 0 # reset the users step back to 0
|
||||
elif text == "pussy":
|
||||
elif text == 'Minnie':
|
||||
bot.send_photo(cid, open('kitten.jpg', 'rb'), reply_markup=hideBoard)
|
||||
userStep[cid] = 0
|
||||
else:
|
||||
bot.send_message(cid, "Don't type bullsh*t, if I give you a predefined keyboard!")
|
||||
bot.send_message(cid, "Please, use the predefined keyboard!")
|
||||
bot.send_message(cid, "Please try again")
|
||||
|
||||
|
||||
@ -128,4 +129,5 @@ def command_default(m):
|
||||
# this is the standard reply to a normal message
|
||||
bot.send_message(m.chat.id, "I don't understand \"" + m.text + "\"\nMaybe try the help page at /help")
|
||||
|
||||
|
||||
bot.polling()
|
||||
|
@ -1,3 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# This is a simple echo bot using the decorator mechanism.
|
||||
# It echoes any incoming text messages.
|
||||
|
||||
@ -7,6 +9,7 @@ API_TOKEN = '<api_token>'
|
||||
|
||||
bot = telebot.TeleBot(API_TOKEN)
|
||||
|
||||
|
||||
# Handle '/start' and '/help'
|
||||
@bot.message_handler(commands=['help', 'start'])
|
||||
def send_welcome(message):
|
||||
@ -21,4 +24,5 @@ I am here to echo your kind words back to you. Just say anything nice and I'll s
|
||||
def echo_message(message):
|
||||
bot.reply_to(message, message.text)
|
||||
|
||||
|
||||
bot.polling()
|
||||
|
@ -1,8 +1,9 @@
|
||||
# This example show how to write an inline mode telegramt bot use pyTelegramBotAPI.
|
||||
import telebot
|
||||
import time
|
||||
import sys
|
||||
# This example show how to write an inline mode telegram bot use pyTelegramBotAPI.
|
||||
import logging
|
||||
import sys
|
||||
import time
|
||||
|
||||
import telebot
|
||||
from telebot import types
|
||||
|
||||
API_TOKEN = '<TOKEN>'
|
||||
@ -50,7 +51,7 @@ def query_video(inline_query):
|
||||
print(e)
|
||||
|
||||
|
||||
@bot.inline_handler(lambda query: len(query.query) is 0)
|
||||
@bot.inline_handler(lambda query: len(query.query) == 0)
|
||||
def default_query(inline_query):
|
||||
try:
|
||||
r = types.InlineQueryResultArticle('1', 'default', types.InputTextMessageContent('default'))
|
||||
@ -69,5 +70,5 @@ if __name__ == '__main__':
|
||||
try:
|
||||
main_loop()
|
||||
except KeyboardInterrupt:
|
||||
print >> sys.stderr, '\nExiting by user request.\n'
|
||||
print('\nExiting by user request.\n')
|
||||
sys.exit(0)
|
||||
|
27
examples/inline_keyboard_example.py
Normal file
27
examples/inline_keyboard_example.py
Normal file
@ -0,0 +1,27 @@
|
||||
# This example show how to use inline keyboards and process button presses
|
||||
import telebot
|
||||
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
|
||||
|
||||
TELEGRAM_TOKEN = '<TOKEN>'
|
||||
|
||||
bot = telebot.TeleBot(TELEGRAM_TOKEN)
|
||||
|
||||
def gen_markup():
|
||||
markup = InlineKeyboardMarkup()
|
||||
markup.row_width = 2
|
||||
markup.add(InlineKeyboardButton("Yes", callback_data="cb_yes"),
|
||||
InlineKeyboardButton("No", callback_data="cb_no"))
|
||||
return markup
|
||||
|
||||
@bot.callback_query_handler(func=lambda call: True)
|
||||
def callback_query(call):
|
||||
if call.data == "cb_yes":
|
||||
bot.answer_callback_query(call.id, "Answer is Yes")
|
||||
elif call.data == "cb_no":
|
||||
bot.answer_callback_query(call.id, "Answer is No")
|
||||
|
||||
@bot.message_handler(func=lambda message: True)
|
||||
def message_handler(message):
|
||||
bot.send_message(message.chat.id, "Yes/no?", reply_markup=gen_markup())
|
||||
|
||||
bot.polling(none_stop=True)
|
@ -1,6 +1,5 @@
|
||||
import telebot
|
||||
from telebot.types import LabeledPrice
|
||||
from telebot.types import ShippingOption
|
||||
from telebot.types import LabeledPrice, ShippingOption
|
||||
|
||||
token = '1234567890:AAAABBBBCCCCDDDDeeeeFFFFgggGHHHH'
|
||||
provider_token = '1234567890:TEST:AAAABBBBCCCCDDDD' # @BotFather -> Bot Settings -> Payments
|
||||
|
69
examples/serverless/azure_functions
Normal file
69
examples/serverless/azure_functions
Normal file
@ -0,0 +1,69 @@
|
||||
# Using Azure Functions for serverless bots.
|
||||
# (Thanks to twitter.com/masyan for the idea)
|
||||
|
||||
# By default the Azure Functions url is https://.../api/HttpTrigger for HttpTrigger type.
|
||||
# In this example we will use clear webhook url without /api/ -> https://.../HttpTrigger.
|
||||
# Also we set "authLevel": "anonymous".
|
||||
|
||||
# For HttpTrigger type set "route" and "authLevel" in functions.json
|
||||
# {
|
||||
# "bindings": [
|
||||
# ...
|
||||
# "authLevel": "anonymous"
|
||||
# "route": "HttpTrigger"
|
||||
# ]
|
||||
# }
|
||||
|
||||
# To avoid using /api/ in url set "routePrefix":"" in host.json
|
||||
# {
|
||||
# ...
|
||||
# "extensions": {
|
||||
# "http": {
|
||||
# "routePrefix": ""
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
|
||||
import logging
|
||||
|
||||
import azure.functions as func
|
||||
import telebot
|
||||
from telebot import apihelper, types
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.DEBUG)
|
||||
|
||||
# Set bot token
|
||||
TOKEN = ''
|
||||
|
||||
# Uncomment this for using proxy for request
|
||||
# PROXY = ''
|
||||
# apihelper.proxy = {'https': PROXY}
|
||||
|
||||
# Set WEBHOOK as your Azure Functions url (https://...azurewebsites.net/HttpTrigger)
|
||||
WEBHOOK = ''
|
||||
|
||||
bot = telebot.TeleBot(TOKEN)
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
bot.reply_to(message, 'Hello, ' + message.from_user.first_name)
|
||||
|
||||
@bot.message_handler(func=lambda message: True, content_types=['text'])
|
||||
def echo_message(message):
|
||||
bot.reply_to(message, message.text)
|
||||
|
||||
# To avoid "error 429 too many request" set webhook only once. Or use time.sleep(1).
|
||||
def main(req: func.HttpRequest) -> func.HttpResponse:
|
||||
bot.set_webhook(url=WEBHOOK)
|
||||
request_body_dict = req.get_json()
|
||||
update = telebot.types.Update.de_json(request_body_dict)
|
||||
bot.process_new_messages([update.message])
|
||||
return func.HttpResponse(body='', status_code=200)
|
||||
|
||||
# Sometimes "requests" version is important.
|
||||
# azure-functions==1.0.4
|
||||
# PySocks==1.7.1
|
||||
# pyTelegramBotAPI==3.6.6
|
||||
# requests==2.10.0
|
||||
|
@ -2,7 +2,6 @@
|
||||
"""
|
||||
This Example will show you how to use register_next_step handler.
|
||||
"""
|
||||
import time
|
||||
|
||||
import telebot
|
||||
from telebot import types
|
||||
@ -75,4 +74,13 @@ def process_sex_step(message):
|
||||
bot.reply_to(message, 'oooops')
|
||||
|
||||
|
||||
# Enable saving next step handlers to file "./.handlers-saves/step.save".
|
||||
# Delay=2 means that after any change in next step handlers (e.g. calling register_next_step_handler())
|
||||
# saving will hapen after delay 2 seconds.
|
||||
bot.enable_save_next_step_handlers(delay=2)
|
||||
|
||||
# Load next_step_handlers from save file (default "./.handlers-saves/step.save")
|
||||
# WARNING It will work only if enable_save_next_step_handlers was called!
|
||||
bot.load_next_step_handlers()
|
||||
|
||||
bot.polling()
|
||||
|
@ -3,9 +3,10 @@
|
||||
# and goes by the name 'TeleBot (@pyTeleBot)'. Join our group to talk to him!
|
||||
# WARNING: Tested with Python 2.7
|
||||
|
||||
import telebot
|
||||
import os
|
||||
|
||||
import telebot
|
||||
|
||||
text_messages = {
|
||||
'welcome':
|
||||
u'Please welcome {name}!\n\n'
|
||||
@ -33,8 +34,10 @@ if "TELEBOT_BOT_TOKEN" not in os.environ or "GROUP_CHAT_ID" not in os.environ:
|
||||
bot = telebot.AsyncTeleBot(os.environ["TELEBOT_BOT_TOKEN"])
|
||||
GROUP_CHAT_ID = int(os.environ["GROUP_CHAT_ID"])
|
||||
|
||||
|
||||
def is_api_group(chat_id):
|
||||
return chat_id== GROUP_CHAT_ID
|
||||
return chat_id == GROUP_CHAT_ID
|
||||
|
||||
|
||||
@bot.message_handler(func=lambda m: True, content_types=['new_chat_participant'])
|
||||
def on_user_joins(message):
|
||||
@ -50,6 +53,7 @@ def on_user_joins(message):
|
||||
|
||||
bot.reply_to(message, text_messages['welcome'].format(name=name))
|
||||
|
||||
|
||||
@bot.message_handler(commands=['info', 'help'])
|
||||
def on_info(message):
|
||||
if not is_api_group(message.chat.id):
|
||||
@ -58,21 +62,23 @@ def on_info(message):
|
||||
|
||||
bot.reply_to(message, text_messages['info'])
|
||||
|
||||
|
||||
@bot.message_handler(commands=["ping"])
|
||||
def on_ping(message):
|
||||
bot.reply_to(message, "Still alive and kicking!")
|
||||
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
def on_start(message):
|
||||
if not is_api_group(message.chat.id):
|
||||
bot.reply_to(message, text_messages['wrong_chat'])
|
||||
return
|
||||
|
||||
|
||||
def listener(messages):
|
||||
for m in messages:
|
||||
print str(m)
|
||||
print(str(m))
|
||||
|
||||
|
||||
bot.set_update_listener(listener)
|
||||
bot.polling()
|
||||
|
||||
|
||||
|
@ -11,7 +11,6 @@ from aiohttp import web
|
||||
|
||||
import telebot
|
||||
|
||||
|
||||
API_TOKEN = '<api_token>'
|
||||
|
||||
WEBHOOK_HOST = '<ip/host where the bot is running>'
|
||||
@ -32,7 +31,6 @@ WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
|
||||
WEBHOOK_URL_BASE = "https://{}:{}".format(WEBHOOK_HOST, WEBHOOK_PORT)
|
||||
WEBHOOK_URL_PATH = "/{}/".format(API_TOKEN)
|
||||
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.INFO)
|
||||
|
||||
@ -51,6 +49,7 @@ async def handle(request):
|
||||
else:
|
||||
return web.Response(status=403)
|
||||
|
||||
|
||||
app.router.add_post('/{token}/', handle)
|
||||
|
||||
|
||||
@ -72,7 +71,7 @@ def echo_message(message):
|
||||
bot.remove_webhook()
|
||||
|
||||
# Set webhook
|
||||
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
|
||||
bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
|
||||
certificate=open(WEBHOOK_SSL_CERT, 'r'))
|
||||
|
||||
# Build ssl context
|
||||
|
@ -4,10 +4,11 @@
|
||||
# This is a simple echo bot using decorators and webhook with CherryPy
|
||||
# It echoes any incoming text messages and does not use the polling method.
|
||||
|
||||
import cherrypy
|
||||
import telebot
|
||||
import logging
|
||||
|
||||
import cherrypy
|
||||
|
||||
import telebot
|
||||
|
||||
API_TOKEN = '<api_token>'
|
||||
|
||||
@ -29,7 +30,6 @@ WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
|
||||
WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT)
|
||||
WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN)
|
||||
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.INFO)
|
||||
|
||||
@ -70,7 +70,7 @@ def echo_message(message):
|
||||
bot.remove_webhook()
|
||||
|
||||
# Set webhook
|
||||
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
|
||||
bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
|
||||
certificate=open(WEBHOOK_SSL_CERT, 'r'))
|
||||
|
||||
# Disable CherryPy requests log
|
||||
@ -80,9 +80,9 @@ for handler in tuple(access_log.handlers):
|
||||
|
||||
# Start cherrypy server
|
||||
cherrypy.config.update({
|
||||
'server.socket_host': WEBHOOK_LISTEN,
|
||||
'server.socket_port': WEBHOOK_PORT,
|
||||
'server.ssl_module': 'builtin',
|
||||
'server.socket_host' : WEBHOOK_LISTEN,
|
||||
'server.socket_port' : WEBHOOK_PORT,
|
||||
'server.ssl_module' : 'builtin',
|
||||
'server.ssl_certificate': WEBHOOK_SSL_CERT,
|
||||
'server.ssl_private_key': WEBHOOK_SSL_PRIV
|
||||
})
|
||||
|
@ -4,11 +4,17 @@
|
||||
# This is a simple echo bot using decorators and webhook with BaseHTTPServer
|
||||
# It echoes any incoming text messages and does not use the polling method.
|
||||
|
||||
import BaseHTTPServer
|
||||
import ssl
|
||||
import telebot
|
||||
import logging
|
||||
try:
|
||||
# Python 2
|
||||
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
||||
except ImportError:
|
||||
# Python 3
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
|
||||
import logging
|
||||
import ssl
|
||||
|
||||
import telebot
|
||||
|
||||
API_TOKEN = '<api_token>'
|
||||
|
||||
@ -30,7 +36,6 @@ WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
|
||||
WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT)
|
||||
WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN)
|
||||
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.INFO)
|
||||
|
||||
@ -38,7 +43,7 @@ bot = telebot.TeleBot(API_TOKEN)
|
||||
|
||||
|
||||
# WebhookHandler, process webhook calls
|
||||
class WebhookHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
class WebhookHandler(BaseHTTPRequestHandler):
|
||||
server_version = "WebhookHandler/1.0"
|
||||
|
||||
def do_HEAD(self):
|
||||
@ -81,15 +86,17 @@ def echo_message(message):
|
||||
|
||||
|
||||
# Remove webhook, it fails sometimes the set if there is a previous webhook
|
||||
bot.remove_webhook()
|
||||
#bot.remove_webhook()
|
||||
|
||||
# Set webhook
|
||||
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
|
||||
certificate=open(WEBHOOK_SSL_CERT, 'r'))
|
||||
# Beacuse telegram bot api server will check webhook server is alive.
|
||||
# Here we need set webhook after server started manually.
|
||||
#bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
|
||||
# certificate=open(WEBHOOK_SSL_CERT, 'r'))
|
||||
|
||||
# Start server
|
||||
httpd = BaseHTTPServer.HTTPServer((WEBHOOK_LISTEN, WEBHOOK_PORT),
|
||||
WebhookHandler)
|
||||
httpd = HTTPServer((WEBHOOK_LISTEN, WEBHOOK_PORT),
|
||||
WebhookHandler)
|
||||
|
||||
httpd.socket = ssl.wrap_socket(httpd.socket,
|
||||
certfile=WEBHOOK_SSL_CERT,
|
||||
|
@ -4,10 +4,12 @@
|
||||
# This is a simple echo bot using decorators and webhook with flask
|
||||
# It echoes any incoming text messages and does not use the polling method.
|
||||
|
||||
import flask
|
||||
import telebot
|
||||
import logging
|
||||
import time
|
||||
|
||||
import flask
|
||||
|
||||
import telebot
|
||||
|
||||
API_TOKEN = '<api_token>'
|
||||
|
||||
@ -29,7 +31,6 @@ WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
|
||||
WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT)
|
||||
WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN)
|
||||
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.INFO)
|
||||
|
||||
@ -73,8 +74,10 @@ def echo_message(message):
|
||||
# Remove webhook, it fails sometimes the set if there is a previous webhook
|
||||
bot.remove_webhook()
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
# Set webhook
|
||||
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
|
||||
bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
|
||||
certificate=open(WEBHOOK_SSL_CERT, 'r'))
|
||||
|
||||
# Start flask server
|
||||
|
@ -1,29 +1,36 @@
|
||||
import telebot
|
||||
import os
|
||||
|
||||
from flask import Flask, request
|
||||
|
||||
bot = telebot.TeleBot('<api_token>')
|
||||
import telebot
|
||||
|
||||
TOKEN = '<api_token>'
|
||||
bot = telebot.TeleBot(TOKEN)
|
||||
server = Flask(__name__)
|
||||
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
bot.reply_to(message, 'Hello, ' + message.from_user.first_name)
|
||||
|
||||
|
||||
@bot.message_handler(func=lambda message: True, content_types=['text'])
|
||||
def echo_message(message):
|
||||
bot.reply_to(message, message.text)
|
||||
|
||||
@server.route("/bot", methods=['POST'])
|
||||
|
||||
@server.route('/' + TOKEN, methods=['POST'])
|
||||
def getMessage():
|
||||
bot.process_new_updates([telebot.types.Update.de_json(request.stream.read().decode("utf-8"))])
|
||||
return "!", 200
|
||||
|
||||
|
||||
@server.route("/")
|
||||
def webhook():
|
||||
bot.remove_webhook()
|
||||
bot.set_webhook(url="https://herokuProject_url/bot")
|
||||
bot.set_webhook(url='https://your_heroku_project.com/' + TOKEN)
|
||||
return "!", 200
|
||||
|
||||
server.run(host="0.0.0.0", port=os.environ.get('PORT', 5000))
|
||||
server = Flask(__name__)
|
||||
|
||||
if __name__ == "__main__":
|
||||
server.run(host="0.0.0.0", port=int(os.environ.get('PORT', 5000)))
|
||||
|
@ -4,13 +4,15 @@
|
||||
# This example shows webhook echo bot with Tornado web framework
|
||||
# Documenation to Tornado: http://tornadoweb.org
|
||||
|
||||
import telebot
|
||||
import tornado.web
|
||||
import tornado.ioloop
|
||||
import tornado.httpserver
|
||||
import tornado.options
|
||||
import signal
|
||||
|
||||
import tornado.httpserver
|
||||
import tornado.ioloop
|
||||
import tornado.options
|
||||
import tornado.web
|
||||
|
||||
import telebot
|
||||
|
||||
API_TOKEN = '<api_token>'
|
||||
WEBHOOK_CERT = "./cert.pem"
|
||||
WEBHOOK_PKEY = "./pkey.pem"
|
||||
@ -29,15 +31,18 @@ WEBHOOK_URL_BASE = "https://{0}:{1}/{2}".format(WEBHOOK_HOST, str(WEBHOOK_PORT),
|
||||
|
||||
bot = telebot.TeleBot(API_TOKEN)
|
||||
|
||||
|
||||
class Root(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
self.write("Hi! This is webhook example!")
|
||||
self.finish()
|
||||
|
||||
|
||||
class webhook_serv(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
self.write("What are you doing here?")
|
||||
self.finish()
|
||||
|
||||
def post(self):
|
||||
if "Content-Length" in self.request.headers and \
|
||||
"Content-Type" in self.request.headers and \
|
||||
@ -52,21 +57,26 @@ class webhook_serv(tornado.web.RequestHandler):
|
||||
else:
|
||||
self.write("What are you doing here?")
|
||||
self.finish()
|
||||
|
||||
|
||||
|
||||
tornado.options.define("port", default=WEBHOOK_PORT, help="run on the given port", type=int)
|
||||
is_closing = False
|
||||
|
||||
|
||||
def signal_handler(signum, frame):
|
||||
global is_closing
|
||||
print("Exiting...")
|
||||
is_closing = True
|
||||
|
||||
|
||||
def try_exit():
|
||||
global is_closing
|
||||
if is_closing:
|
||||
# clean up here
|
||||
tornado.ioloop.IOLoop.instance().stop()
|
||||
print("Exit success!")
|
||||
|
||||
|
||||
|
||||
# Handle '/start' and '/help'
|
||||
@bot.message_handler(commands=['help', 'start'])
|
||||
def send_welcome(message):
|
||||
@ -74,6 +84,7 @@ def send_welcome(message):
|
||||
("Hi there, I am EchoBot.\n"
|
||||
"I am here to echo your kind words back to you."))
|
||||
|
||||
|
||||
bot.remove_webhook()
|
||||
bot.set_webhook(url=WEBHOOK_URL_BASE,
|
||||
certificate=open(WEBHOOK_CERT, 'r'))
|
||||
@ -86,9 +97,9 @@ application = tornado.web.Application([
|
||||
])
|
||||
|
||||
http_server = tornado.httpserver.HTTPServer(application, ssl_options={
|
||||
"certfile": WEBHOOK_CERT,
|
||||
"keyfile": WEBHOOK_PKEY,
|
||||
})
|
||||
"certfile": WEBHOOK_CERT,
|
||||
"keyfile" : WEBHOOK_PKEY,
|
||||
})
|
||||
http_server.listen(tornado.options.options.port)
|
||||
tornado.ioloop.PeriodicCallback(try_exit, 100).start()
|
||||
tornado.ioloop.IOLoop.instance().start()
|
||||
|
@ -1,5 +1,5 @@
|
||||
py==1.4.29
|
||||
pytest==3.0.2
|
||||
requests==2.7.0
|
||||
requests==2.20.0
|
||||
six==1.9.0
|
||||
wheel==0.24.0
|
||||
|
12
setup.py
12
setup.py
@ -2,14 +2,15 @@
|
||||
from setuptools import setup
|
||||
from io import open
|
||||
|
||||
def readme():
|
||||
with open('README.rst', encoding='utf-8') as f:
|
||||
return f.read()
|
||||
def read(filename):
|
||||
with open(filename, encoding='utf-8') as file:
|
||||
return file.read()
|
||||
|
||||
setup(name='pyTelegramBotAPI',
|
||||
version='3.1.1',
|
||||
version='3.6.6',
|
||||
description='Python Telegram bot api. ',
|
||||
long_description=readme(),
|
||||
long_description=read('README.md'),
|
||||
long_description_content_type="text/markdown",
|
||||
author='eternnoir',
|
||||
author_email='eternnoir@gmail.com',
|
||||
url='https://github.com/eternnoir/pyTelegramBotAPI',
|
||||
@ -23,7 +24,6 @@ setup(name='pyTelegramBotAPI',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Environment :: Console',
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,18 +20,18 @@ from telebot import util
|
||||
logger = telebot.logger
|
||||
proxy = None
|
||||
|
||||
API_URL = "https://api.telegram.org/bot{0}/{1}"
|
||||
FILE_URL = "https://api.telegram.org/file/bot{0}/{1}"
|
||||
API_URL = None
|
||||
FILE_URL = None
|
||||
|
||||
CONNECT_TIMEOUT = 3.5
|
||||
READ_TIMEOUT = 9999
|
||||
|
||||
|
||||
def _get_req_session():
|
||||
return util.per_thread('req_session', lambda: requests.session())
|
||||
def _get_req_session(reset=False):
|
||||
return util.per_thread('req_session', lambda: requests.session(), reset)
|
||||
|
||||
|
||||
def _make_request(token, method_name, method='get', params=None, files=None, base_url=API_URL):
|
||||
def _make_request(token, method_name, method='get', params=None, files=None):
|
||||
"""
|
||||
Makes a request to the Telegram API.
|
||||
:param token: The bot's API token. (Created with @BotFather)
|
||||
@ -41,7 +41,11 @@ def _make_request(token, method_name, method='get', params=None, files=None, bas
|
||||
:param files: Optional files.
|
||||
:return: The result parsed to a JSON dictionary.
|
||||
"""
|
||||
request_url = base_url.format(token, method_name)
|
||||
if API_URL is None:
|
||||
request_url = "https://api.telegram.org/bot{0}/{1}".format(token, method_name)
|
||||
else:
|
||||
request_url = API_URL.format(token, method_name)
|
||||
|
||||
logger.debug("Request: method={0} url={1} params={2} files={3}".format(method, request_url, params, files))
|
||||
read_timeout = READ_TIMEOUT
|
||||
connect_timeout = CONNECT_TIMEOUT
|
||||
@ -98,9 +102,20 @@ def get_file(token, file_id):
|
||||
return _make_request(token, method_url, params={'file_id': file_id})
|
||||
|
||||
|
||||
def get_file_url(token, file_id):
|
||||
if FILE_URL is None:
|
||||
return "https://api.telegram.org/file/bot{0}/{1}".format(token, get_file(token, file_id)['file_path'])
|
||||
else:
|
||||
return FILE_URL.format(token, get_file(token, file_id)['file_path'])
|
||||
|
||||
|
||||
def download_file(token, file_path):
|
||||
url = FILE_URL.format(token, file_path)
|
||||
result = _get_req_session().get(url)
|
||||
if FILE_URL is None:
|
||||
url = "https://api.telegram.org/file/bot{0}/{1}".format(token, file_path)
|
||||
else:
|
||||
url = FILE_URL.format(token, file_path)
|
||||
|
||||
result = _get_req_session().get(url, proxies=proxy)
|
||||
if result.status_code != 200:
|
||||
msg = 'The server returned HTTP {0} {1}. Response body:\n[{2}]' \
|
||||
.format(result.status_code, result.reason, result.text)
|
||||
@ -109,7 +124,7 @@ def download_file(token, file_path):
|
||||
|
||||
|
||||
def send_message(token, chat_id, text, disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None,
|
||||
parse_mode=None, disable_notification=None):
|
||||
parse_mode=None, disable_notification=None, timeout=None):
|
||||
"""
|
||||
Use this method to send text messages. On success, the sent Message is returned.
|
||||
:param token:
|
||||
@ -118,6 +133,8 @@ def send_message(token, chat_id, text, disable_web_page_preview=None, reply_to_m
|
||||
:param disable_web_page_preview:
|
||||
:param reply_to_message_id:
|
||||
:param reply_markup:
|
||||
:param parse_mode:
|
||||
:param disable_notification:
|
||||
:return:
|
||||
"""
|
||||
method_url = r'sendMessage'
|
||||
@ -132,6 +149,8 @@ def send_message(token, chat_id, text, disable_web_page_preview=None, reply_to_m
|
||||
payload['parse_mode'] = parse_mode
|
||||
if disable_notification:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
@ -209,6 +228,18 @@ def get_chat_members_count(token, chat_id):
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def set_chat_sticker_set(token, chat_id, sticker_set_name):
|
||||
method_url = r'setChatStickerSet'
|
||||
payload = {'chat_id': chat_id, 'sticker_set_name': sticker_set_name}
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def delete_chat_sticker_set(token, chat_id):
|
||||
method_url = r'deleteChatStickerSet'
|
||||
payload = {'chat_id': chat_id}
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def get_chat_member(token, chat_id, user_id):
|
||||
method_url = r'getChatMember'
|
||||
payload = {'chat_id': chat_id, 'user_id': user_id}
|
||||
@ -224,7 +255,7 @@ def forward_message(token, chat_id, from_chat_id, message_id, disable_notificati
|
||||
|
||||
|
||||
def send_photo(token, chat_id, photo, caption=None, reply_to_message_id=None, reply_markup=None,
|
||||
disable_notification=None):
|
||||
parse_mode=None, disable_notification=None):
|
||||
method_url = r'sendPhoto'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
@ -238,15 +269,31 @@ def send_photo(token, chat_id, photo, caption=None, reply_to_message_id=None, re
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if parse_mode:
|
||||
payload['parse_mode'] = parse_mode
|
||||
if disable_notification:
|
||||
payload['disable_notification'] = disable_notification
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
def send_location(token, chat_id, latitude, longitude, reply_to_message_id=None, reply_markup=None,
|
||||
def send_media_group(token, chat_id, media, disable_notification=None, reply_to_message_id=None):
|
||||
method_url = r'sendMediaGroup'
|
||||
media_json, files = _convert_input_media_array(media)
|
||||
payload = {'chat_id': chat_id, 'media': media_json}
|
||||
if disable_notification:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if reply_to_message_id:
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
return _make_request(token, method_url, params=payload, method='post' if files else 'get',
|
||||
files=files if files else None)
|
||||
|
||||
|
||||
def send_location(token, chat_id, latitude, longitude, live_period=None, reply_to_message_id=None, reply_markup=None,
|
||||
disable_notification=None):
|
||||
method_url = r'sendLocation'
|
||||
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
|
||||
if live_period:
|
||||
payload['live_period'] = live_period
|
||||
if reply_to_message_id:
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
if reply_markup:
|
||||
@ -256,6 +303,36 @@ def send_location(token, chat_id, latitude, longitude, reply_to_message_id=None,
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def edit_message_live_location(token, latitude, longitude, chat_id=None, message_id=None,
|
||||
inline_message_id=None, reply_markup=None):
|
||||
method_url = r'editMessageLiveLocation'
|
||||
payload = {'latitude': latitude, 'longitude': longitude}
|
||||
if chat_id:
|
||||
payload['chat_id'] = chat_id
|
||||
if message_id:
|
||||
payload['message_id'] = message_id
|
||||
if inline_message_id:
|
||||
payload['inline_message_id'] = inline_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def stop_message_live_location(token, chat_id=None, message_id=None,
|
||||
inline_message_id=None, reply_markup=None):
|
||||
method_url = r'stopMessageLiveLocation'
|
||||
payload = {}
|
||||
if chat_id:
|
||||
payload['chat_id'] = chat_id
|
||||
if message_id:
|
||||
payload['message_id'] = message_id
|
||||
if inline_message_id:
|
||||
payload['inline_message_id'] = inline_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def send_venue(token, chat_id, latitude, longitude, title, address, foursquare_id=None, disable_notification=None,
|
||||
reply_to_message_id=None, reply_markup=None):
|
||||
method_url = r'sendVenue'
|
||||
@ -293,7 +370,7 @@ def send_chat_action(token, chat_id, action):
|
||||
|
||||
|
||||
def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
|
||||
disable_notification=None, timeout=None):
|
||||
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None):
|
||||
method_url = r'sendVideo'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
@ -309,6 +386,36 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if parse_mode:
|
||||
payload['parse_mode'] = parse_mode
|
||||
if supports_streaming:
|
||||
payload['supports_streaming'] = supports_streaming
|
||||
if disable_notification:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
def send_animation(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
|
||||
parse_mode=None, disable_notification=None, timeout=None):
|
||||
method_url = r'sendAnimation'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
if not util.is_string(data):
|
||||
files = {'animation': data}
|
||||
else:
|
||||
payload['animation'] = data
|
||||
if duration:
|
||||
payload['duration'] = duration
|
||||
if caption:
|
||||
payload['caption'] = caption
|
||||
if reply_to_message_id:
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if parse_mode:
|
||||
payload['parse_mode'] = parse_mode
|
||||
if disable_notification:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
@ -317,7 +424,7 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa
|
||||
|
||||
|
||||
def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_message_id=None, reply_markup=None,
|
||||
disable_notification=None, timeout=None):
|
||||
parse_mode=None, disable_notification=None, timeout=None):
|
||||
method_url = r'sendVoice'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
@ -333,6 +440,8 @@ def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_mess
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if parse_mode:
|
||||
payload['parse_mode'] = parse_mode
|
||||
if disable_notification:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
@ -367,7 +476,7 @@ def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_m
|
||||
|
||||
|
||||
def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None, reply_to_message_id=None,
|
||||
reply_markup=None, disable_notification=None, timeout=None):
|
||||
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None):
|
||||
method_url = r'sendAudio'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
@ -387,6 +496,8 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if parse_mode:
|
||||
payload['parse_mode'] = parse_mode
|
||||
if disable_notification:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
@ -394,8 +505,8 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None, disable_notification=None,
|
||||
timeout=None, caption=None):
|
||||
def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None, parse_mode=None,
|
||||
disable_notification=None, timeout=None, caption=None):
|
||||
method_url = get_method_by_type(data_type)
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
@ -407,6 +518,8 @@ def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_m
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if parse_mode and data_type == 'document':
|
||||
payload['parse_mode'] = parse_mode
|
||||
if disable_notification:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
@ -545,10 +658,11 @@ def edit_message_text(token, text, chat_id=None, message_id=None, inline_message
|
||||
payload['disable_web_page_preview'] = disable_web_page_preview
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
return _make_request(token, method_url, params=payload)
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
|
||||
def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_message_id=None,
|
||||
parse_mode=None, reply_markup=None):
|
||||
method_url = r'editMessageCaption'
|
||||
payload = {'caption': caption}
|
||||
if chat_id:
|
||||
@ -557,9 +671,26 @@ def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_m
|
||||
payload['message_id'] = message_id
|
||||
if inline_message_id:
|
||||
payload['inline_message_id'] = inline_message_id
|
||||
if parse_mode:
|
||||
payload['parse_mode'] = parse_mode
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
return _make_request(token, method_url, params=payload)
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def edit_message_media(token, media, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
|
||||
method_url = r'editMessageMedia'
|
||||
media_json, file = _convert_input_media(media)
|
||||
payload = {'media': media_json}
|
||||
if chat_id:
|
||||
payload['chat_id'] = chat_id
|
||||
if message_id:
|
||||
payload['message_id'] = message_id
|
||||
if inline_message_id:
|
||||
payload['inline_message_id'] = inline_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
return _make_request(token, method_url, params=payload, files=file, method='post' if file else 'get')
|
||||
|
||||
|
||||
def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
|
||||
@ -573,13 +704,13 @@ def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_messa
|
||||
payload['inline_message_id'] = inline_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
return _make_request(token, method_url, params=payload)
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def delete_message(token, chat_id, message_id):
|
||||
method_url = r'deleteMessage'
|
||||
payload = {'chat_id': chat_id, 'message_id': message_id}
|
||||
return _make_request(token, method_url, params=payload)
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
# Game
|
||||
@ -654,7 +785,7 @@ def get_game_high_scores(token, user_id, chat_id=None, message_id=None, inline_m
|
||||
def send_invoice(token, chat_id, title, description, invoice_payload, provider_token, currency, prices,
|
||||
start_parameter, photo_url=None, photo_size=None, photo_width=None, photo_height=None,
|
||||
need_name=None, need_phone_number=None, need_email=None, need_shipping_address=None, is_flexible=None,
|
||||
disable_notification=None, reply_to_message_id=None, reply_markup=None):
|
||||
disable_notification=None, reply_to_message_id=None, reply_markup=None, provider_data=None):
|
||||
"""
|
||||
Use this method to send invoices. On success, the sent Message is returned.
|
||||
:param token: Bot's token (you don't need to fill this)
|
||||
@ -678,7 +809,8 @@ def send_invoice(token, chat_id, title, description, invoice_payload, provider_t
|
||||
:param disable_notification: Sends the message silently. Users will receive a notification with no sound.
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param reply_markup: A JSON-serialized object for an inline keyboard. If empty, one 'Pay total price' button will be shown. If not empty, the first button must be a Pay button
|
||||
:return:
|
||||
:param provider_data:
|
||||
:return:
|
||||
"""
|
||||
method_url = r'sendInvoice'
|
||||
payload = {'chat_id': chat_id, 'title': title, 'description': description, 'payload': invoice_payload,
|
||||
@ -708,6 +840,8 @@ def send_invoice(token, chat_id, title, description, invoice_payload, provider_t
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if provider_data:
|
||||
payload['provider_data'] = provider_data
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
@ -719,12 +853,12 @@ def answer_shipping_query(token, shipping_query_id, ok, shipping_options=None, e
|
||||
:param ok: Specify True if delivery to the specified address is possible and False if there are any problems (for example, if delivery to the specified address is not possible)
|
||||
:param shipping_options: Required if ok is True. A JSON-serialized array of available shipping options.
|
||||
:param error_message: Required if ok is False. Error message in human readable form that explains why it is impossible to complete the order (e.g. "Sorry, delivery to your desired address is unavailable'). Telegram will display this message to the user.
|
||||
:return:
|
||||
:return:
|
||||
"""
|
||||
method_url = 'answerShippingQuery'
|
||||
payload = {'shipping_query_id': shipping_query_id, 'ok': ok}
|
||||
if shipping_options:
|
||||
payload['reply_markup'] = _convert_list_json_serializable(shipping_options)
|
||||
payload['shipping_options'] = _convert_list_json_serializable(shipping_options)
|
||||
if error_message:
|
||||
payload['error_message'] = error_message
|
||||
return _make_request(token, method_url, params=payload)
|
||||
@ -737,7 +871,7 @@ def answer_pre_checkout_query(token, pre_checkout_query_id, ok, error_message=No
|
||||
:param pre_checkout_query_id: Unique identifier for the query to be answered
|
||||
:param ok: Specify True if everything is alright (goods are available, etc.) and the bot is ready to proceed with the order. Use False if there are any problems.
|
||||
:param error_message: Required if ok is False. Error message in human readable form that explains the reason for failure to proceed with the checkout (e.g. "Sorry, somebody just bought the last of our amazing black T-shirts while you were busy filling out your payment details. Please choose a different color or garment!"). Telegram will display this message to the user.
|
||||
:return:
|
||||
:return:
|
||||
"""
|
||||
method_url = 'answerPreCheckoutQuery'
|
||||
payload = {'pre_checkout_query_id': pre_checkout_query_id, 'ok': ok}
|
||||
@ -769,7 +903,7 @@ def answer_callback_query(token, callback_query_id, text=None, show_alert=None,
|
||||
payload['show_alert'] = show_alert
|
||||
if url:
|
||||
payload['url'] = url
|
||||
if cache_time:
|
||||
if cache_time is not None:
|
||||
payload['cache_time'] = cache_time
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
@ -778,7 +912,7 @@ def answer_inline_query(token, inline_query_id, results, cache_time=None, is_per
|
||||
switch_pm_text=None, switch_pm_parameter=None):
|
||||
method_url = 'answerInlineQuery'
|
||||
payload = {'inline_query_id': inline_query_id, 'results': _convert_list_json_serializable(results)}
|
||||
if cache_time:
|
||||
if cache_time is not None:
|
||||
payload['cache_time'] = cache_time
|
||||
if is_personal:
|
||||
payload['is_personal'] = is_personal
|
||||
@ -843,6 +977,26 @@ def delete_sticker_from_set(token, sticker):
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def send_poll(token, chat_id, question, options, disable_notifications=False, reply_to_message_id=None, reply_markup=None):
|
||||
method_url = r'sendPoll'
|
||||
payload = {'chat_id': str(chat_id), 'question': question, 'options': _convert_list_json_serializable(options)}
|
||||
if disable_notifications:
|
||||
payload['disable_notification'] = disable_notifications
|
||||
if reply_to_message_id:
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def stop_poll(token, chat_id, message_id, reply_markup=None):
|
||||
method_url = r'stopPoll'
|
||||
payload = {'chat_id': str(chat_id), 'message_id': message_id}
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def _convert_list_json_serializable(results):
|
||||
ret = ''
|
||||
for r in results:
|
||||
@ -859,10 +1013,29 @@ def _convert_markup(markup):
|
||||
return markup
|
||||
|
||||
|
||||
def _convert_input_media(media):
|
||||
if isinstance(media, types.InputMedia):
|
||||
return media._convert_input_media()
|
||||
return None, None
|
||||
|
||||
|
||||
def _convert_input_media_array(array):
|
||||
media = []
|
||||
files = {}
|
||||
for input_media in array:
|
||||
if isinstance(input_media, types.InputMedia):
|
||||
media_dict = input_media.to_dic()
|
||||
if media_dict['media'].startswith('attach://'):
|
||||
key = media_dict['media'].replace('attach://', '')
|
||||
files[key] = input_media.media
|
||||
media.append(media_dict)
|
||||
return json.dumps(media), files
|
||||
|
||||
|
||||
def _no_encode(func):
|
||||
def wrapper(key, val):
|
||||
if key == 'filename':
|
||||
return '{0}={1}'.format(key, val)
|
||||
return u'{0}={1}'.format(key, val)
|
||||
else:
|
||||
return func(key, val)
|
||||
|
||||
|
443
telebot/types.py
443
telebot/types.py
@ -10,7 +10,7 @@ import six
|
||||
from telebot import util
|
||||
|
||||
|
||||
class JsonSerializable:
|
||||
class JsonSerializable(object):
|
||||
"""
|
||||
Subclasses of this class are guaranteed to be able to be converted to JSON format.
|
||||
All subclasses of this class must override to_json.
|
||||
@ -26,7 +26,7 @@ class JsonSerializable:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Dictionaryable:
|
||||
class Dictionaryable(object):
|
||||
"""
|
||||
Subclasses of this class are guaranteed to be able to be converted to dictionary.
|
||||
All subclasses of this class must override to_dic.
|
||||
@ -42,7 +42,7 @@ class Dictionaryable:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class JsonDeserializable:
|
||||
class JsonDeserializable(object):
|
||||
"""
|
||||
Subclasses of this class are guaranteed to be able to be created from a json-style dict or json formatted string.
|
||||
All subclasses of this class must override de_json.
|
||||
@ -127,7 +127,6 @@ class Update(JsonDeserializable):
|
||||
def __init__(self, update_id, message, edited_message, channel_post, edited_channel_post, inline_query,
|
||||
chosen_inline_result, callback_query, shipping_query, pre_checkout_query):
|
||||
self.update_id = update_id
|
||||
self.edited_message = edited_message
|
||||
self.message = message
|
||||
self.edited_message = edited_message
|
||||
self.channel_post = channel_post
|
||||
@ -177,14 +176,16 @@ class User(JsonDeserializable):
|
||||
def de_json(cls, json_string):
|
||||
obj = cls.check_json(json_string)
|
||||
id = obj['id']
|
||||
is_bot = obj['is_bot']
|
||||
first_name = obj['first_name']
|
||||
last_name = obj.get('last_name')
|
||||
username = obj.get('username')
|
||||
language_code = obj.get('language_code')
|
||||
return cls(id, first_name, last_name, username, language_code)
|
||||
return cls(id, is_bot, first_name, last_name, username, language_code)
|
||||
|
||||
def __init__(self, id, first_name, last_name=None, username=None, language_code=None):
|
||||
def __init__(self, id, is_bot, first_name, last_name=None, username=None, language_code=None):
|
||||
self.id = id
|
||||
self.is_bot = is_bot
|
||||
self.first_name = first_name
|
||||
self.username = username
|
||||
self.last_name = last_name
|
||||
@ -220,11 +221,17 @@ class Chat(JsonDeserializable):
|
||||
photo = ChatPhoto.de_json(obj['photo'])
|
||||
description = obj.get('description')
|
||||
invite_link = obj.get('invite_link')
|
||||
pinned_message = None
|
||||
if 'pinned_message' in obj:
|
||||
pinned_message = Message.de_json(obj['pinned_message'])
|
||||
sticker_set_name = obj.get('sticker_set_name')
|
||||
can_set_sticker_set = obj.get('can_set_sticker_set')
|
||||
return cls(id, type, title, username, first_name, last_name, all_members_are_administrators,
|
||||
photo, description, invite_link)
|
||||
photo, description, invite_link, pinned_message, sticker_set_name, can_set_sticker_set)
|
||||
|
||||
def __init__(self, id, type, title=None, username=None, first_name=None, last_name=None,
|
||||
all_members_are_administrators=None, photo=None, description=None, invite_link=None):
|
||||
all_members_are_administrators=None, photo=None, description=None, invite_link=None,
|
||||
pinned_message=None, sticker_set_name=None, can_set_sticker_set=None):
|
||||
self.type = type
|
||||
self.last_name = last_name
|
||||
self.first_name = first_name
|
||||
@ -235,6 +242,9 @@ class Chat(JsonDeserializable):
|
||||
self.photo = photo
|
||||
self.description = description
|
||||
self.invite_link = invite_link
|
||||
self.pinned_message = pinned_message
|
||||
self.sticker_set_name = sticker_set_name
|
||||
self.can_set_sticker_set = can_set_sticker_set
|
||||
|
||||
|
||||
class Message(JsonDeserializable):
|
||||
@ -255,20 +265,31 @@ class Message(JsonDeserializable):
|
||||
opts['forward_from_chat'] = Chat.de_json(obj['forward_from_chat'])
|
||||
if 'forward_from_message_id' in obj:
|
||||
opts['forward_from_message_id'] = obj.get('forward_from_message_id')
|
||||
if 'forward_signature' in obj:
|
||||
opts['forward_signature'] = obj.get('forward_signature')
|
||||
if 'forward_date' in obj:
|
||||
opts['forward_date'] = obj.get('forward_date')
|
||||
if 'reply_to_message' in obj:
|
||||
opts['reply_to_message'] = Message.de_json(obj['reply_to_message'])
|
||||
if 'edit_date' in obj:
|
||||
opts['edit_date'] = obj.get('edit_date')
|
||||
if 'media_group_id' in obj:
|
||||
opts['media_group_id'] = obj.get('media_group_id')
|
||||
if 'author_signature' in obj:
|
||||
opts['author_signature'] = obj.get('author_signature')
|
||||
if 'text' in obj:
|
||||
opts['text'] = obj['text']
|
||||
content_type = 'text'
|
||||
if 'entities' in obj:
|
||||
opts['entities'] = Message.parse_entities(obj['entities'])
|
||||
if 'caption_entities' in obj:
|
||||
opts['caption_entities'] = Message.parse_entities(obj['caption_entities'])
|
||||
if 'audio' in obj:
|
||||
opts['audio'] = Audio.de_json(obj['audio'])
|
||||
content_type = 'audio'
|
||||
if 'animation' in obj:
|
||||
opts['animation'] = Animation.de_json(obj['animation'])
|
||||
content_type = 'animation'
|
||||
if 'document' in obj:
|
||||
opts['document'] = Document.de_json(obj['document'])
|
||||
content_type = 'document'
|
||||
@ -316,29 +337,47 @@ class Message(JsonDeserializable):
|
||||
content_type = 'left_chat_member'
|
||||
if 'new_chat_title' in obj:
|
||||
opts['new_chat_title'] = obj['new_chat_title']
|
||||
content_type = 'new_chat_title'
|
||||
if 'new_chat_photo' in obj:
|
||||
opts['new_chat_photo'] = Message.parse_photo(obj['new_chat_photo'])
|
||||
content_type = 'new_chat_photo'
|
||||
if 'delete_chat_photo' in obj:
|
||||
opts['delete_chat_photo'] = obj['delete_chat_photo']
|
||||
content_type = 'delete_chat_photo'
|
||||
if 'group_chat_created' in obj:
|
||||
opts['group_chat_created'] = obj['group_chat_created']
|
||||
content_type = 'group_chat_created'
|
||||
if 'supergroup_chat_created' in obj:
|
||||
opts['supergroup_chat_created'] = obj['supergroup_chat_created']
|
||||
content_type = 'supergroup_chat_created'
|
||||
if 'channel_chat_created' in obj:
|
||||
opts['channel_chat_created'] = obj['channel_chat_created']
|
||||
content_type = 'channel_chat_created'
|
||||
if 'migrate_to_chat_id' in obj:
|
||||
opts['migrate_to_chat_id'] = obj['migrate_to_chat_id']
|
||||
content_type = 'migrate_to_chat_id'
|
||||
if 'migrate_from_chat_id' in obj:
|
||||
opts['migrate_from_chat_id'] = obj['migrate_from_chat_id']
|
||||
content_type = 'migrate_from_chat_id'
|
||||
if 'pinned_message' in obj:
|
||||
opts['pinned_message'] = Message.de_json(obj['pinned_message'])
|
||||
content_type = 'pinned_message'
|
||||
if 'invoice' in obj:
|
||||
opts['invoice'] = Invoice.de_json(obj['invoice'])
|
||||
content_type = 'invoice'
|
||||
if 'successful_payment' in obj:
|
||||
opts['successful_payment'] = SuccessfulPayment.de_json(obj['successful_payment'])
|
||||
content_type = 'successful_payment'
|
||||
return cls(message_id, from_user, date, chat, content_type, opts)
|
||||
if 'connected_website' in obj:
|
||||
opts['connected_website'] = obj['connected_website']
|
||||
content_type = 'connected_website'
|
||||
if 'poll' in obj:
|
||||
opts['poll'] = Poll.de_json(obj['poll'])
|
||||
content_type = 'poll'
|
||||
if 'passport_data' in obj:
|
||||
opts['passport_data'] = obj['passport_data']
|
||||
content_type = 'passport_data'
|
||||
return cls(message_id, from_user, date, chat, content_type, opts, json_string)
|
||||
|
||||
@classmethod
|
||||
def parse_chat(cls, chat):
|
||||
@ -361,19 +400,23 @@ class Message(JsonDeserializable):
|
||||
ret.append(MessageEntity.de_json(me))
|
||||
return ret
|
||||
|
||||
def __init__(self, message_id, from_user, date, chat, content_type, options):
|
||||
def __init__(self, message_id, from_user, date, chat, content_type, options, json_string):
|
||||
self.content_type = content_type
|
||||
self.message_id = message_id
|
||||
self.from_user = from_user
|
||||
self.date = date
|
||||
self.chat = chat
|
||||
self.forward_from_chat = None
|
||||
self.forward_from_message_id = None
|
||||
self.forward_from = None
|
||||
self.forward_date = None
|
||||
self.reply_to_message = None
|
||||
self.edit_date = None
|
||||
self.media_group_id = None
|
||||
self.author_signature = None
|
||||
self.text = None
|
||||
self.entities = None
|
||||
self.caption_entities = None
|
||||
self.audio = None
|
||||
self.document = None
|
||||
self.photo = None
|
||||
@ -385,6 +428,7 @@ class Message(JsonDeserializable):
|
||||
self.contact = None
|
||||
self.location = None
|
||||
self.venue = None
|
||||
self.animation = None
|
||||
self.new_chat_member = None
|
||||
self.new_chat_members = None
|
||||
self.left_chat_member = None
|
||||
@ -399,8 +443,75 @@ class Message(JsonDeserializable):
|
||||
self.pinned_message = None
|
||||
self.invoice = None
|
||||
self.successful_payment = None
|
||||
self.connected_website = None
|
||||
for key in options:
|
||||
setattr(self, key, options[key])
|
||||
self.json = json_string
|
||||
|
||||
def __html_text(self, text, entities):
|
||||
"""
|
||||
Author: @sviat9440
|
||||
Message: "*Test* parse _formatting_, [url](https://example.com), [text_mention](tg://user?id=123456) and mention @username"
|
||||
|
||||
Example:
|
||||
message.html_text
|
||||
>> "<b>Test</b> parse <i>formatting</i>, <a href=\"https://example.com\">url</a>, <a href=\"tg://user?id=123456\">text_mention</a> and mention @username"
|
||||
|
||||
Cusom subs:
|
||||
You can customize the substitutes. By default, there is no substitute for the entities: hashtag, bot_command, email. You can add or modify substitute an existing entity.
|
||||
Example:
|
||||
message.custom_subs = {"bold": "<strong class=\"example\">{text}</strong>", "italic": "<i class=\"example\">{text}</i>", "mention": "<a href={url}>{text}</a>"}
|
||||
message.html_text
|
||||
>> "<strong class=\"example\">Test</strong> parse <i class=\"example\">formatting</i>, <a href=\"https://example.com\">url</a> and <a href=\"tg://user?id=123456\">text_mention</a> and mention <a href=\"https://t.me/username\">@username</a>"
|
||||
"""
|
||||
|
||||
if not entities:
|
||||
return text
|
||||
_subs = {
|
||||
"bold" : "<b>{text}</b>",
|
||||
"italic" : "<i>{text}</i>",
|
||||
"pre" : "<pre>{text}</pre>",
|
||||
"code" : "<code>{text}</code>",
|
||||
"url" : "<a href=\"{url}\">{text}</a>",
|
||||
"text_link": "<a href=\"{url}\">{text}</a>"
|
||||
}
|
||||
if hasattr(self, "custom_subs"):
|
||||
for type in self.custom_subs:
|
||||
_subs[type] = self.custom_subs[type]
|
||||
utf16_text = text.encode("utf-16-le")
|
||||
html_text = ""
|
||||
|
||||
def func(text, type=None, url=None, user=None):
|
||||
text = text.decode("utf-16-le")
|
||||
if type == "text_mention":
|
||||
type = "url"
|
||||
url = "tg://user?id={0}".format(user.id)
|
||||
elif type == "mention":
|
||||
url = "https://t.me/{0}".format(text[1:])
|
||||
text = text.replace("&", "&").replace("<", "<").replace(">", ">")
|
||||
if not type or not _subs.get(type):
|
||||
return text
|
||||
subs = _subs.get(type)
|
||||
return subs.format(text=text, url=url)
|
||||
|
||||
offset = 0
|
||||
for entity in entities:
|
||||
if entity.offset > offset:
|
||||
html_text += func(utf16_text[offset * 2 : entity.offset * 2])
|
||||
offset = entity.offset
|
||||
html_text += func(utf16_text[offset * 2 : (offset + entity.length) * 2], entity.type, entity.url, entity.user)
|
||||
offset += entity.length
|
||||
if offset * 2 < len(utf16_text):
|
||||
html_text += func(utf16_text[offset * 2:])
|
||||
return html_text
|
||||
|
||||
@property
|
||||
def html_text(self):
|
||||
return self.__html_text(self.text, self.entities)
|
||||
|
||||
@property
|
||||
def html_caption(self):
|
||||
return self.__html_text(self.caption, self.caption_entities)
|
||||
|
||||
|
||||
class MessageEntity(JsonDeserializable):
|
||||
@ -500,29 +611,6 @@ class Document(JsonDeserializable):
|
||||
self.file_size = file_size
|
||||
|
||||
|
||||
class Sticker(JsonDeserializable):
|
||||
@classmethod
|
||||
def de_json(cls, json_string):
|
||||
obj = cls.check_json(json_string)
|
||||
file_id = obj['file_id']
|
||||
width = obj['width']
|
||||
height = obj['height']
|
||||
thumb = None
|
||||
if 'thumb' in obj:
|
||||
thumb = PhotoSize.de_json(obj['thumb'])
|
||||
emoji = obj.get('emoji')
|
||||
file_size = obj.get('file_size')
|
||||
return cls(file_id, width, height, thumb, emoji, file_size)
|
||||
|
||||
def __init__(self, file_id, width, height, thumb, emoji=None, file_size=None):
|
||||
self.file_id = file_id
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.thumb = thumb
|
||||
self.emoji = emoji
|
||||
self.file_size = file_size
|
||||
|
||||
|
||||
class Video(JsonDeserializable):
|
||||
@classmethod
|
||||
def de_json(cls, json_string):
|
||||
@ -808,9 +896,30 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable):
|
||||
return json_dict
|
||||
|
||||
|
||||
class LoginUrl(JsonSerializable):
|
||||
def __init__(self, url, forward_text=None, bot_username=None, request_write_access=None):
|
||||
self.url = url
|
||||
self.forward_text = forward_text
|
||||
self.bot_username = bot_username
|
||||
self.request_write_access = request_write_access
|
||||
|
||||
def to_json(self):
|
||||
return json.dumps(self.to_dic())
|
||||
|
||||
def to_dic(self):
|
||||
json_dic = {'url': self.url}
|
||||
if self.forward_text:
|
||||
json_dic['forward_text'] = self.forward_text
|
||||
if self.bot_username:
|
||||
json_dic['bot_username'] = self.bot_username
|
||||
if self.request_write_access:
|
||||
json_dic['request_write_access'] = self.request_write_access
|
||||
return json_dic
|
||||
|
||||
|
||||
class InlineKeyboardButton(JsonSerializable):
|
||||
def __init__(self, text, url=None, callback_data=None, switch_inline_query=None,
|
||||
switch_inline_query_current_chat=None, callback_game=None, pay=None):
|
||||
switch_inline_query_current_chat=None, callback_game=None, pay=None, login_url=None):
|
||||
self.text = text
|
||||
self.url = url
|
||||
self.callback_data = callback_data
|
||||
@ -818,6 +927,7 @@ class InlineKeyboardButton(JsonSerializable):
|
||||
self.switch_inline_query_current_chat = switch_inline_query_current_chat
|
||||
self.callback_game = callback_game
|
||||
self.pay = pay
|
||||
self.login_url = login_url
|
||||
|
||||
def to_json(self):
|
||||
return json.dumps(self.to_dic())
|
||||
@ -836,6 +946,8 @@ class InlineKeyboardButton(JsonSerializable):
|
||||
json_dic['callback_game'] = self.callback_game
|
||||
if self.pay is not None:
|
||||
json_dic['pay'] = self.pay
|
||||
if self.login_url is not None:
|
||||
json_dic['login_url'] = self.login_url.to_dic()
|
||||
return json_dic
|
||||
|
||||
|
||||
@ -972,12 +1084,15 @@ class InputTextMessageContent(Dictionaryable):
|
||||
|
||||
|
||||
class InputLocationMessageContent(Dictionaryable):
|
||||
def __init__(self, latitude, longitude):
|
||||
def __init__(self, latitude, longitude, live_period=None):
|
||||
self.latitude = latitude
|
||||
self.longitude = longitude
|
||||
self.live_period = live_period
|
||||
|
||||
def to_dic(self):
|
||||
json_dic = {'latitude': self.latitude, 'longitude': self.longitude}
|
||||
if self.live_period:
|
||||
json_dic['live_period'] = self.live_period
|
||||
return json_dic
|
||||
|
||||
|
||||
@ -991,7 +1106,7 @@ class InputVenueMessageContent(Dictionaryable):
|
||||
|
||||
def to_dic(self):
|
||||
json_dic = {'latitude': self.latitude, 'longitude': self.longitude, 'title': self.title,
|
||||
'address': self.address}
|
||||
'address' : self.address}
|
||||
if self.foursquare_id:
|
||||
json_dic['foursquare_id'] = self.foursquare_id
|
||||
return json_dic
|
||||
@ -1090,7 +1205,7 @@ class InlineQueryResultArticle(JsonSerializable):
|
||||
|
||||
class InlineQueryResultPhoto(JsonSerializable):
|
||||
def __init__(self, id, photo_url, thumb_url, photo_width=None, photo_height=None, title=None,
|
||||
description=None, caption=None, reply_markup=None, input_message_content=None):
|
||||
description=None, caption=None, parse_mode=None, reply_markup=None, input_message_content=None):
|
||||
"""
|
||||
Represents a link to a photo.
|
||||
:param id: Unique identifier for this result, 1-64 bytes
|
||||
@ -1101,6 +1216,8 @@ class InlineQueryResultPhoto(JsonSerializable):
|
||||
:param title: Title for the result.
|
||||
:param description: Short description of the result.
|
||||
:param caption: Caption of the photo to be sent, 0-200 characters.
|
||||
:param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or
|
||||
inline URLs in the media caption.
|
||||
:param reply_markup: InlineKeyboardMarkup : Inline keyboard attached to the message
|
||||
:param input_message_content: InputMessageContent : Content of the message to be sent instead of the photo
|
||||
:return:
|
||||
@ -1114,6 +1231,7 @@ class InlineQueryResultPhoto(JsonSerializable):
|
||||
self.title = title
|
||||
self.description = description
|
||||
self.caption = caption
|
||||
self.parse_mode = parse_mode
|
||||
self.reply_markup = reply_markup
|
||||
self.input_message_content = input_message_content
|
||||
|
||||
@ -1129,6 +1247,8 @@ class InlineQueryResultPhoto(JsonSerializable):
|
||||
json_dict['description'] = self.description
|
||||
if self.caption:
|
||||
json_dict['caption'] = self.caption
|
||||
if self.parse_mode:
|
||||
json_dict['parse_mode'] = self.parse_mode
|
||||
if self.reply_markup:
|
||||
json_dict['reply_markup'] = self.reply_markup.to_dic()
|
||||
if self.input_message_content:
|
||||
@ -1185,7 +1305,7 @@ class InlineQueryResultGif(JsonSerializable):
|
||||
|
||||
class InlineQueryResultMpeg4Gif(JsonSerializable):
|
||||
def __init__(self, id, mpeg4_url, thumb_url, mpeg4_width=None, mpeg4_height=None, title=None, caption=None,
|
||||
reply_markup=None, input_message_content=None, mpeg4_duration=None):
|
||||
parse_mode=None, reply_markup=None, input_message_content=None, mpeg4_duration=None):
|
||||
"""
|
||||
Represents a link to a video animation (H.264/MPEG-4 AVC video without sound).
|
||||
:param id: Unique identifier for this result, 1-64 bytes
|
||||
@ -1195,6 +1315,8 @@ class InlineQueryResultMpeg4Gif(JsonSerializable):
|
||||
:param mpeg4_height: Video height
|
||||
:param title: Title for the result
|
||||
:param caption: Caption of the MPEG-4 file to be sent, 0-200 characters
|
||||
:param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text
|
||||
or inline URLs in the media caption.
|
||||
:param reply_markup: InlineKeyboardMarkup : Inline keyboard attached to the message
|
||||
:param input_message_content: InputMessageContent : Content of the message to be sent instead of the photo
|
||||
:return:
|
||||
@ -1207,6 +1329,7 @@ class InlineQueryResultMpeg4Gif(JsonSerializable):
|
||||
self.thumb_url = thumb_url
|
||||
self.title = title
|
||||
self.caption = caption
|
||||
self.parse_mode = parse_mode
|
||||
self.reply_markup = reply_markup
|
||||
self.input_message_content = input_message_content
|
||||
self.mpeg4_duration = mpeg4_duration
|
||||
@ -1221,6 +1344,8 @@ class InlineQueryResultMpeg4Gif(JsonSerializable):
|
||||
json_dict['title'] = self.title
|
||||
if self.caption:
|
||||
json_dict['caption'] = self.caption
|
||||
if self.parse_mode:
|
||||
json_dict['parse_mode'] = self.parse_mode
|
||||
if self.reply_markup:
|
||||
json_dict['reply_markup'] = self.reply_markup.to_dic()
|
||||
if self.input_message_content:
|
||||
@ -1232,8 +1357,8 @@ class InlineQueryResultMpeg4Gif(JsonSerializable):
|
||||
|
||||
class InlineQueryResultVideo(JsonSerializable):
|
||||
def __init__(self, id, video_url, mime_type, thumb_url, title,
|
||||
caption=None, video_width=None, video_height=None, video_duration=None, description=None,
|
||||
reply_markup=None, input_message_content=None):
|
||||
caption=None, parse_mode=None, video_width=None, video_height=None, video_duration=None,
|
||||
description=None, reply_markup=None, input_message_content=None):
|
||||
"""
|
||||
Represents link to a page containing an embedded video player or a video file.
|
||||
:param id: Unique identifier for this result, 1-64 bytes
|
||||
@ -1241,6 +1366,8 @@ class InlineQueryResultVideo(JsonSerializable):
|
||||
:param mime_type: Mime type of the content of video url, “text/html” or “video/mp4”
|
||||
:param thumb_url: URL of the thumbnail (jpeg only) for the video
|
||||
:param title: Title for the result
|
||||
:param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or
|
||||
inline URLs in the media caption.
|
||||
:param video_width: Video width
|
||||
:param video_height: Video height
|
||||
:param video_duration: Video duration in seconds
|
||||
@ -1257,6 +1384,7 @@ class InlineQueryResultVideo(JsonSerializable):
|
||||
self.thumb_url = thumb_url
|
||||
self.title = title
|
||||
self.caption = caption
|
||||
self.parse_mode = parse_mode
|
||||
self.description = description
|
||||
self.input_message_content = input_message_content
|
||||
self.reply_markup = reply_markup
|
||||
@ -1274,6 +1402,8 @@ class InlineQueryResultVideo(JsonSerializable):
|
||||
json_dict['description'] = self.description
|
||||
if self.caption:
|
||||
json_dict['caption'] = self.caption
|
||||
if self.parse_mode:
|
||||
json_dict['parse_mode'] = self.parse_mode
|
||||
if self.reply_markup:
|
||||
json_dict['reply_markup'] = self.reply_markup.to_dic()
|
||||
if self.input_message_content:
|
||||
@ -1282,13 +1412,14 @@ class InlineQueryResultVideo(JsonSerializable):
|
||||
|
||||
|
||||
class InlineQueryResultAudio(JsonSerializable):
|
||||
def __init__(self, id, audio_url, title, caption=None, performer=None, audio_duration=None, reply_markup=None,
|
||||
input_message_content=None):
|
||||
def __init__(self, id, audio_url, title, caption=None, parse_mode=None, performer=None, audio_duration=None,
|
||||
reply_markup=None, input_message_content=None):
|
||||
self.type = 'audio'
|
||||
self.id = id
|
||||
self.audio_url = audio_url
|
||||
self.title = title
|
||||
self.caption = caption
|
||||
self.parse_mode = parse_mode
|
||||
self.performer = performer
|
||||
self.audio_duration = audio_duration
|
||||
self.reply_markup = reply_markup
|
||||
@ -1298,6 +1429,8 @@ class InlineQueryResultAudio(JsonSerializable):
|
||||
json_dict = {'type': self.type, 'id': self.id, 'audio_url': self.audio_url, 'title': self.title}
|
||||
if self.caption:
|
||||
json_dict['caption'] = self.caption
|
||||
if self.parse_mode:
|
||||
json_dict['parse_mode'] = self.parse_mode
|
||||
if self.performer:
|
||||
json_dict['performer'] = self.performer
|
||||
if self.audio_duration:
|
||||
@ -1310,13 +1443,14 @@ class InlineQueryResultAudio(JsonSerializable):
|
||||
|
||||
|
||||
class InlineQueryResultVoice(JsonSerializable):
|
||||
def __init__(self, id, voice_url, title, caption=None, performer=None, voice_duration=None, reply_markup=None,
|
||||
input_message_content=None):
|
||||
def __init__(self, id, voice_url, title, caption=None, parse_mode=None, performer=None, voice_duration=None,
|
||||
reply_markup=None, input_message_content=None):
|
||||
self.type = 'voice'
|
||||
self.id = id
|
||||
self.voice_url = voice_url
|
||||
self.title = title
|
||||
self.caption = caption
|
||||
self.parse_mode = parse_mode
|
||||
self.performer = performer
|
||||
self.voice_duration = voice_duration
|
||||
self.reply_markup = reply_markup
|
||||
@ -1326,6 +1460,8 @@ class InlineQueryResultVoice(JsonSerializable):
|
||||
json_dict = {'type': self.type, 'id': self.id, 'voice_url': self.voice_url, 'title': self.title}
|
||||
if self.caption:
|
||||
json_dict['caption'] = self.caption
|
||||
if self.parse_mode:
|
||||
json_dict['parse_mode'] = self.parse_mode
|
||||
if self.performer:
|
||||
json_dict['performer'] = self.performer
|
||||
if self.voice_duration:
|
||||
@ -1338,14 +1474,15 @@ class InlineQueryResultVoice(JsonSerializable):
|
||||
|
||||
|
||||
class InlineQueryResultDocument(JsonSerializable):
|
||||
def __init__(self, id, title, document_url, mime_type, caption=None, description=None, reply_markup=None,
|
||||
input_message_content=None, thumb_url=None, thumb_width=None, thumb_height=None):
|
||||
def __init__(self, id, title, document_url, mime_type, caption=None, parse_mode=None, description=None,
|
||||
reply_markup=None, input_message_content=None, thumb_url=None, thumb_width=None, thumb_height=None):
|
||||
self.type = 'document'
|
||||
self.id = id
|
||||
self.title = title
|
||||
self.document_url = document_url
|
||||
self.mime_type = mime_type
|
||||
self.caption = caption
|
||||
self.parse_mode = parse_mode
|
||||
self.description = description
|
||||
self.reply_markup = reply_markup
|
||||
self.input_message_content = input_message_content
|
||||
@ -1358,6 +1495,8 @@ class InlineQueryResultDocument(JsonSerializable):
|
||||
'mime_type': self.mime_type}
|
||||
if self.caption:
|
||||
json_dict['caption'] = self.caption
|
||||
if self.parse_mode:
|
||||
json_dict['parse_mode'] = self.parse_mode
|
||||
if self.description:
|
||||
json_dict['description'] = self.description
|
||||
if self.thumb_url:
|
||||
@ -1374,13 +1513,14 @@ class InlineQueryResultDocument(JsonSerializable):
|
||||
|
||||
|
||||
class InlineQueryResultLocation(JsonSerializable):
|
||||
def __init__(self, id, title, latitude, longitude, reply_markup=None,
|
||||
def __init__(self, id, title, latitude, longitude, live_period=None, reply_markup=None,
|
||||
input_message_content=None, thumb_url=None, thumb_width=None, thumb_height=None):
|
||||
self.type = 'location'
|
||||
self.id = id
|
||||
self.title = title
|
||||
self.latitude = latitude
|
||||
self.longitude = longitude
|
||||
self.live_period = live_period
|
||||
self.reply_markup = reply_markup
|
||||
self.input_message_content = input_message_content
|
||||
self.thumb_url = thumb_url
|
||||
@ -1390,6 +1530,8 @@ class InlineQueryResultLocation(JsonSerializable):
|
||||
def to_json(self):
|
||||
json_dict = {'type': self.type, 'id': self.id, 'latitude': self.latitude, 'longitude': self.longitude,
|
||||
'title': self.title}
|
||||
if self.live_period:
|
||||
json_dict['live_period'] = self.live_period
|
||||
if self.thumb_url:
|
||||
json_dict['thumb_url'] = self.thumb_url
|
||||
if self.thumb_width:
|
||||
@ -1477,6 +1619,7 @@ class BaseInlineQueryResultCached(JsonSerializable):
|
||||
self.caption = None
|
||||
self.reply_markup = None
|
||||
self.input_message_content = None
|
||||
self.parse_mode = None
|
||||
self.payload_dic = {}
|
||||
|
||||
def to_json(self):
|
||||
@ -1493,12 +1636,14 @@ class BaseInlineQueryResultCached(JsonSerializable):
|
||||
json_dict['reply_markup'] = self.reply_markup.to_dic()
|
||||
if self.input_message_content:
|
||||
json_dict['input_message_content'] = self.input_message_content.to_dic()
|
||||
if self.parse_mode:
|
||||
json_dict['parse_mode'] = self.parse_mode
|
||||
return json.dumps(json_dict)
|
||||
|
||||
|
||||
class InlineQueryResultCachedPhoto(BaseInlineQueryResultCached):
|
||||
def __init__(self, id, photo_file_id, title=None, description=None, caption=None, reply_markup=None,
|
||||
input_message_content=None):
|
||||
def __init__(self, id, photo_file_id, title=None, description=None, caption=None, parse_mode=None,
|
||||
reply_markup=None, input_message_content=None):
|
||||
BaseInlineQueryResultCached.__init__(self)
|
||||
self.type = 'photo'
|
||||
self.id = id
|
||||
@ -1508,11 +1653,12 @@ class InlineQueryResultCachedPhoto(BaseInlineQueryResultCached):
|
||||
self.caption = caption
|
||||
self.reply_markup = reply_markup
|
||||
self.input_message_content = input_message_content
|
||||
self.parse_mode = parse_mode
|
||||
self.payload_dic['photo_file_id'] = photo_file_id
|
||||
|
||||
|
||||
class InlineQueryResultCachedGif(BaseInlineQueryResultCached):
|
||||
def __init__(self, id, gif_file_id, title=None, description=None, caption=None, reply_markup=None,
|
||||
def __init__(self, id, gif_file_id, title=None, description=None, caption=None, parse_mode=None, reply_markup=None,
|
||||
input_message_content=None):
|
||||
BaseInlineQueryResultCached.__init__(self)
|
||||
self.type = 'gif'
|
||||
@ -1523,12 +1669,13 @@ class InlineQueryResultCachedGif(BaseInlineQueryResultCached):
|
||||
self.caption = caption
|
||||
self.reply_markup = reply_markup
|
||||
self.input_message_content = input_message_content
|
||||
self.parse_mode = parse_mode
|
||||
self.payload_dic['gif_file_id'] = gif_file_id
|
||||
|
||||
|
||||
class InlineQueryResultCachedMpeg4Gif(BaseInlineQueryResultCached):
|
||||
def __init__(self, id, mpeg4_file_id, title=None, description=None, caption=None, reply_markup=None,
|
||||
input_message_content=None):
|
||||
def __init__(self, id, mpeg4_file_id, title=None, description=None, caption=None, parse_mode=None,
|
||||
reply_markup=None, input_message_content=None):
|
||||
BaseInlineQueryResultCached.__init__(self)
|
||||
self.type = 'mpeg4_gif'
|
||||
self.id = id
|
||||
@ -1538,6 +1685,7 @@ class InlineQueryResultCachedMpeg4Gif(BaseInlineQueryResultCached):
|
||||
self.caption = caption
|
||||
self.reply_markup = reply_markup
|
||||
self.input_message_content = input_message_content
|
||||
self.parse_mode = parse_mode
|
||||
self.payload_dic['mpeg4_file_id'] = mpeg4_file_id
|
||||
|
||||
|
||||
@ -1553,7 +1701,7 @@ class InlineQueryResultCachedSticker(BaseInlineQueryResultCached):
|
||||
|
||||
|
||||
class InlineQueryResultCachedDocument(BaseInlineQueryResultCached):
|
||||
def __init__(self, id, document_file_id, title, description=None, caption=None, reply_markup=None,
|
||||
def __init__(self, id, document_file_id, title, description=None, caption=None, parse_mode=None, reply_markup=None,
|
||||
input_message_content=None):
|
||||
BaseInlineQueryResultCached.__init__(self)
|
||||
self.type = 'document'
|
||||
@ -1564,11 +1712,12 @@ class InlineQueryResultCachedDocument(BaseInlineQueryResultCached):
|
||||
self.caption = caption
|
||||
self.reply_markup = reply_markup
|
||||
self.input_message_content = input_message_content
|
||||
self.parse_mode = parse_mode
|
||||
self.payload_dic['document_file_id'] = document_file_id
|
||||
|
||||
|
||||
class InlineQueryResultCachedVideo(BaseInlineQueryResultCached):
|
||||
def __init__(self, id, video_file_id, title, description=None, caption=None, reply_markup=None,
|
||||
def __init__(self, id, video_file_id, title, description=None, caption=None, parse_mode=None, reply_markup=None,
|
||||
input_message_content=None):
|
||||
BaseInlineQueryResultCached.__init__(self)
|
||||
self.type = 'video'
|
||||
@ -1579,11 +1728,13 @@ class InlineQueryResultCachedVideo(BaseInlineQueryResultCached):
|
||||
self.caption = caption
|
||||
self.reply_markup = reply_markup
|
||||
self.input_message_content = input_message_content
|
||||
self.parse_mode = parse_mode
|
||||
self.payload_dic['video_file_id'] = video_file_id
|
||||
|
||||
|
||||
class InlineQueryResultCachedVoice(BaseInlineQueryResultCached):
|
||||
def __init__(self, id, voice_file_id, title, caption=None, reply_markup=None, input_message_content=None):
|
||||
def __init__(self, id, voice_file_id, title, caption=None, parse_mode=None, reply_markup=None,
|
||||
input_message_content=None):
|
||||
BaseInlineQueryResultCached.__init__(self)
|
||||
self.type = 'voice'
|
||||
self.id = id
|
||||
@ -1592,11 +1743,12 @@ class InlineQueryResultCachedVoice(BaseInlineQueryResultCached):
|
||||
self.caption = caption
|
||||
self.reply_markup = reply_markup
|
||||
self.input_message_content = input_message_content
|
||||
self.parse_mode = parse_mode
|
||||
self.payload_dic['voice_file_id'] = voice_file_id
|
||||
|
||||
|
||||
class InlineQueryResultCachedAudio(BaseInlineQueryResultCached):
|
||||
def __init__(self, id, audio_file_id, caption=None, reply_markup=None, input_message_content=None):
|
||||
def __init__(self, id, audio_file_id, caption=None, parse_mode=None, reply_markup=None, input_message_content=None):
|
||||
BaseInlineQueryResultCached.__init__(self)
|
||||
self.type = 'audio'
|
||||
self.id = id
|
||||
@ -1604,6 +1756,7 @@ class InlineQueryResultCachedAudio(BaseInlineQueryResultCached):
|
||||
self.caption = caption
|
||||
self.reply_markup = reply_markup
|
||||
self.input_message_content = input_message_content
|
||||
self.parse_mode = parse_mode
|
||||
self.payload_dic['audio_file_id'] = audio_file_id
|
||||
|
||||
|
||||
@ -1780,16 +1933,17 @@ class ShippingOption(JsonSerializable):
|
||||
def add_price(self, *args):
|
||||
"""
|
||||
Add LabeledPrice to ShippingOption
|
||||
:param args: LabeledPrices
|
||||
:param args: LabeledPrices
|
||||
"""
|
||||
for price in args:
|
||||
self.prices.append(price)
|
||||
return self
|
||||
|
||||
def to_json(self):
|
||||
price_list = []
|
||||
for p in self.prices:
|
||||
price_list.append(p.to_dic())
|
||||
json_dict = {'id': self.id, 'title': self.title, 'prices': price_list}
|
||||
json_dict = json.dumps({'id': self.id, 'title': self.title, 'prices': price_list})
|
||||
return json_dict
|
||||
|
||||
|
||||
@ -1890,6 +2044,7 @@ class Sticker(JsonDeserializable):
|
||||
file_id = obj['file_id']
|
||||
width = obj['width']
|
||||
height = obj['height']
|
||||
is_animated = obj['is_animated']
|
||||
thumb = None
|
||||
if 'thumb' in obj:
|
||||
thumb = PhotoSize.de_json(obj['thumb'])
|
||||
@ -1899,9 +2054,9 @@ class Sticker(JsonDeserializable):
|
||||
if 'mask_position' in obj:
|
||||
mask_position = MaskPosition.de_json(obj['mask_position'])
|
||||
file_size = obj.get('file_size')
|
||||
return cls(file_id, width, height, thumb, emoji, set_name, mask_position, file_size)
|
||||
return cls(file_id, width, height, thumb, emoji, set_name, mask_position, file_size, is_animated)
|
||||
|
||||
def __init__(self, file_id, width, height, thumb, emoji, set_name, mask_position, file_size):
|
||||
def __init__(self, file_id, width, height, thumb, emoji, set_name, mask_position, file_size, is_animated):
|
||||
self.file_id = file_id
|
||||
self.width = width
|
||||
self.height = height
|
||||
@ -1910,7 +2065,7 @@ class Sticker(JsonDeserializable):
|
||||
self.set_name = set_name
|
||||
self.mask_position = mask_position
|
||||
self.file_size = file_size
|
||||
|
||||
self.is_animated = is_animated
|
||||
|
||||
class MaskPosition(JsonDeserializable, JsonSerializable):
|
||||
@classmethod
|
||||
@ -1934,3 +2089,169 @@ class MaskPosition(JsonDeserializable, JsonSerializable):
|
||||
def to_dic(self):
|
||||
return {'point': self.point, 'x_shift': self.x_shift, 'y_shift': self.y_shift, 'scale': self.scale}
|
||||
|
||||
|
||||
# InputMedia
|
||||
|
||||
class InputMedia(JsonSerializable):
|
||||
def __init__(self, type, media, caption=None, parse_mode=None):
|
||||
self.type = type
|
||||
self.media = media
|
||||
self.caption = caption
|
||||
self.parse_mode = parse_mode
|
||||
|
||||
if util.is_string(self.media):
|
||||
self._media_name = ''
|
||||
self._media_dic = self.media
|
||||
else:
|
||||
self._media_name = util.generate_random_token()
|
||||
self._media_dic = 'attach://{0}'.format(self._media_name)
|
||||
|
||||
def to_json(self):
|
||||
return json.dumps(self.to_dic())
|
||||
|
||||
def to_dic(self):
|
||||
ret = {'type': self.type, 'media': self._media_dic}
|
||||
if self.caption:
|
||||
ret['caption'] = self.caption
|
||||
if self.parse_mode:
|
||||
ret['parse_mode'] = self.parse_mode
|
||||
return ret
|
||||
|
||||
def _convert_input_media(self):
|
||||
if util.is_string(self.media):
|
||||
return self.to_json(), None
|
||||
|
||||
return self.to_json(), {self._media_name: self.media}
|
||||
|
||||
|
||||
class InputMediaPhoto(InputMedia):
|
||||
def __init__(self, media, caption=None, parse_mode=None):
|
||||
super(InputMediaPhoto, self).__init__(type="photo", media=media, caption=caption, parse_mode=parse_mode)
|
||||
|
||||
def to_dic(self):
|
||||
ret = super(InputMediaPhoto, self).to_dic()
|
||||
return ret
|
||||
|
||||
|
||||
class InputMediaVideo(InputMedia):
|
||||
def __init__(self, media, thumb=None, caption=None, parse_mode=None, width=None, height=None, duration=None,
|
||||
supports_streaming=None):
|
||||
super(InputMediaVideo, self).__init__(type="video", media=media, caption=caption, parse_mode=parse_mode)
|
||||
self.thumb = thumb
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.duration = duration
|
||||
self.supports_streaming = supports_streaming
|
||||
|
||||
def to_dic(self):
|
||||
ret = super(InputMediaVideo, self).to_dic()
|
||||
if self.thumb:
|
||||
ret['thumb'] = self.thumb
|
||||
if self.width:
|
||||
ret['width'] = self.width
|
||||
if self.height:
|
||||
ret['height'] = self.height
|
||||
if self.duration:
|
||||
ret['duration'] = self.duration
|
||||
if self.supports_streaming:
|
||||
ret['supports_streaming'] = self.supports_streaming
|
||||
return ret
|
||||
|
||||
|
||||
class InputMediaAnimation(InputMedia):
|
||||
def __init__(self, media, thumb=None, caption=None, parse_mode=None, width=None, height=None, duration=None):
|
||||
super(InputMediaAnimation, self).__init__(type="animation", media=media, caption=caption, parse_mode=parse_mode)
|
||||
self.thumb = thumb
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.duration = duration
|
||||
|
||||
def to_dic(self):
|
||||
ret = super(InputMediaAnimation, self).to_dic()
|
||||
if self.thumb:
|
||||
ret['thumb'] = self.thumb
|
||||
if self.width:
|
||||
ret['width'] = self.width
|
||||
if self.height:
|
||||
ret['height'] = self.height
|
||||
if self.duration:
|
||||
ret['duration'] = self.duration
|
||||
return ret
|
||||
|
||||
|
||||
class InputMediaAudio(InputMedia):
|
||||
def __init__(self, media, thumb=None, caption=None, parse_mode=None, duration=None, performer=None, title=None):
|
||||
super(InputMediaAudio, self).__init__(type="audio", media=media, caption=caption, parse_mode=parse_mode)
|
||||
self.thumb = thumb
|
||||
self.duration = duration
|
||||
self.performer = performer
|
||||
self.title = title
|
||||
|
||||
def to_dic(self):
|
||||
ret = super(InputMediaAudio, self).to_dic()
|
||||
if self.thumb:
|
||||
ret['thumb'] = self.thumb
|
||||
if self.duration:
|
||||
ret['duration'] = self.duration
|
||||
if self.performer:
|
||||
ret['performer'] = self.performer
|
||||
if self.title:
|
||||
ret['title'] = self.title
|
||||
return ret
|
||||
|
||||
|
||||
class InputMediaDocument(InputMedia):
|
||||
def __init__(self, media, thumb=None, caption=None, parse_mode=None):
|
||||
super(InputMediaDocument, self).__init__(type="document", media=media, caption=caption, parse_mode=parse_mode)
|
||||
self.thumb = thumb
|
||||
|
||||
def to_dic(self):
|
||||
ret = super(InputMediaDocument, self).to_dic()
|
||||
if self.thumb:
|
||||
ret['thumb'] = self.thumb
|
||||
return ret
|
||||
|
||||
|
||||
class PollOption(JsonSerializable, JsonDeserializable):
|
||||
@classmethod
|
||||
def de_json(cls, json_type):
|
||||
obj = cls.check_json(json_type)
|
||||
text = obj['text']
|
||||
voter_count = int(obj['voter_count'])
|
||||
option = cls(text)
|
||||
option.voter_count = voter_count
|
||||
return option
|
||||
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
self.voter_count = 0
|
||||
|
||||
def to_json(self):
|
||||
return json.dumps(self.text)
|
||||
|
||||
|
||||
class Poll(JsonDeserializable):
|
||||
@classmethod
|
||||
def de_json(cls, json_type):
|
||||
obj = cls.check_json(json_type)
|
||||
poll_id = obj['id']
|
||||
question = obj['question']
|
||||
poll = cls(question)
|
||||
options = []
|
||||
for opt in obj['options']:
|
||||
options.append(PollOption.de_json(opt))
|
||||
poll.options = options
|
||||
is_closed = obj['is_closed']
|
||||
poll.id = poll_id
|
||||
poll.is_closed = is_closed
|
||||
return poll
|
||||
|
||||
def __init__(self, question):
|
||||
self.options = []
|
||||
self.question = question
|
||||
|
||||
def add(self, option):
|
||||
if type(option) is PollOption:
|
||||
self.options.append(option)
|
||||
else:
|
||||
self.options.append(PollOption(option))
|
||||
|
@ -1,9 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
import re
|
||||
import sys
|
||||
|
||||
import six
|
||||
from six import string_types
|
||||
|
||||
@ -13,9 +15,9 @@ try:
|
||||
import Queue
|
||||
except ImportError:
|
||||
import queue as Queue
|
||||
import logging
|
||||
|
||||
from telebot import logger
|
||||
|
||||
logger = logging.getLogger('TeleBot')
|
||||
|
||||
thread_local = threading.local()
|
||||
|
||||
@ -142,7 +144,7 @@ class AsyncTask:
|
||||
return self.result
|
||||
|
||||
|
||||
def async():
|
||||
def async_dec():
|
||||
def decorator(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
return AsyncTask(fn, *args, **kwargs)
|
||||
@ -242,15 +244,18 @@ def extract_arguments(text):
|
||||
:param text: String to extract the arguments from a command
|
||||
:return: the arguments if `text` is a command (according to is_command), else None.
|
||||
"""
|
||||
regexp = re.compile("\/\w*(@\w*)*\s*([\s\S]*)",re.IGNORECASE)
|
||||
regexp = re.compile("/\w*(@\w*)*\s*([\s\S]*)",re.IGNORECASE)
|
||||
result = regexp.match(text)
|
||||
return result.group(2) if is_command(text) else None
|
||||
|
||||
|
||||
def per_thread(key, construct_value):
|
||||
try:
|
||||
return getattr(thread_local, key)
|
||||
except AttributeError:
|
||||
def per_thread(key, construct_value, reset=False):
|
||||
if reset or not hasattr(thread_local, key):
|
||||
value = construct_value()
|
||||
setattr(thread_local, key, value)
|
||||
return value
|
||||
|
||||
return getattr(thread_local, key)
|
||||
|
||||
|
||||
def generate_random_token():
|
||||
return ''.join(random.sample(string.ascii_letters, 16))
|
@ -201,7 +201,8 @@ class TestTeleBot:
|
||||
def test_send_audio_dis_noti(self):
|
||||
file_data = open('./test_data/record.mp3', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ret_msg = tb.send_audio(CHAT_ID, file_data, 1, performer='eternnoir', title='pyTelegram', disable_notification=True)
|
||||
ret_msg = tb.send_audio(CHAT_ID, file_data, 1, performer='eternnoir', title='pyTelegram',
|
||||
disable_notification=True)
|
||||
assert ret_msg.content_type == 'audio'
|
||||
assert ret_msg.audio.performer == 'eternnoir'
|
||||
assert ret_msg.audio.title == 'pyTelegram'
|
||||
@ -360,6 +361,20 @@ class TestTeleBot:
|
||||
new_msg = tb.edit_message_caption(caption='Edit test', chat_id=CHAT_ID, message_id=msg.message_id)
|
||||
assert new_msg.caption == 'Edit test'
|
||||
|
||||
def test_edit_message_media(self):
|
||||
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
|
||||
file_data_2 = open('../examples/detailed_example/rooster.jpg', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
msg = tb.send_photo(CHAT_ID, file_data)
|
||||
new_msg = tb.edit_message_media(chat_id=CHAT_ID, message_id=msg.message_id,
|
||||
media=types.InputMediaPhoto(file_data_2, caption='Test editMessageMedia 0'))
|
||||
assert type(new_msg) != bool
|
||||
|
||||
new_msg = tb.edit_message_media(chat_id=CHAT_ID, message_id=msg.message_id,
|
||||
media=types.InputMediaPhoto(msg.photo[0].file_id, caption='Test editMessageMedia'))
|
||||
assert type(new_msg) != bool
|
||||
assert new_msg.caption == 'Test editMessageMedia'
|
||||
|
||||
def test_get_chat(self):
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ch = tb.get_chat(GROUP_ID)
|
||||
@ -387,10 +402,11 @@ class TestTeleBot:
|
||||
new_msg = tb.edit_message_reply_markup(chat_id=CHAT_ID, message_id=ret_msg.message_id, reply_markup=markup)
|
||||
assert new_msg.message_id
|
||||
|
||||
def create_text_message(self, text):
|
||||
@staticmethod
|
||||
def create_text_message(text):
|
||||
params = {'text': text}
|
||||
chat = types.User(11, 'test')
|
||||
return types.Message(1, None, None, chat, 'text', params)
|
||||
chat = types.User(11, False, 'test')
|
||||
return types.Message(1, None, None, chat, 'text', params, "")
|
||||
|
||||
def test_is_string_unicode(self):
|
||||
s1 = u'string'
|
||||
@ -409,3 +425,67 @@ class TestTeleBot:
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ret_msg = tb.send_video_note(CHAT_ID, file_data)
|
||||
assert ret_msg.message_id
|
||||
|
||||
def test_send_media_group(self):
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
img1 = 'https://i.imgur.com/CjXjcnU.png'
|
||||
img2 = 'https://i.imgur.com/CjXjcnU.png'
|
||||
medias = [types.InputMediaPhoto(img1, "View"), types.InputMediaPhoto(img2, "Dog")]
|
||||
result = tb.send_media_group(CHAT_ID, medias)
|
||||
assert len(result) == 2
|
||||
assert result[0].media_group_id is not None
|
||||
assert result[0].media_group_id == result[1].media_group_id
|
||||
|
||||
def test_send_media_group_local_files(self):
|
||||
photo = open('../examples/detailed_example/kitten.jpg', 'rb')
|
||||
video = open('./test_data/test_video.mp4', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
medias = [types.InputMediaPhoto(photo, "View"),
|
||||
types.InputMediaVideo(video)]
|
||||
result = tb.send_media_group(CHAT_ID, medias)
|
||||
assert len(result) == 2
|
||||
assert result[0].media_group_id is not None
|
||||
assert result[1].media_group_id is not None
|
||||
|
||||
def test_send_photo_formating_caption(self):
|
||||
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ret_msg = tb.send_photo(CHAT_ID, file_data, caption='_italic_', parse_mode='Markdown')
|
||||
assert ret_msg.caption_entities[0].type == 'italic'
|
||||
|
||||
def test_send_video_formatting_caption(self):
|
||||
file_data = open('./test_data/test_video.mp4', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ret_msg = tb.send_video(CHAT_ID, file_data, caption='_italic_', parse_mode='Markdown')
|
||||
assert ret_msg.caption_entities[0].type == 'italic'
|
||||
|
||||
def test_send_audio_formatting_caption(self):
|
||||
file_data = open('./test_data/record.mp3', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ret_msg = tb.send_audio(CHAT_ID, file_data, caption='<b>bold</b>', parse_mode='HTML')
|
||||
assert ret_msg.caption_entities[0].type == 'bold'
|
||||
|
||||
def test_send_voice_formatting_caprion(self):
|
||||
file_data = open('./test_data/record.ogg', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ret_msg = tb.send_voice(CHAT_ID, file_data, caption='<b>bold</b>', parse_mode='HTML')
|
||||
assert ret_msg.caption_entities[0].type == 'bold'
|
||||
assert ret_msg.voice.mime_type == 'audio/ogg'
|
||||
|
||||
def test_send_media_group_formatting_caption(self):
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
img1 = 'https://i.imgur.com/CjXjcnU.png'
|
||||
img2 = 'https://i.imgur.com/CjXjcnU.png'
|
||||
medias = [types.InputMediaPhoto(img1, "*View*", parse_mode='Markdown'),
|
||||
types.InputMediaPhoto(img2, "_Dog_", parse_mode='Markdown')]
|
||||
result = tb.send_media_group(CHAT_ID, medias)
|
||||
assert len(result) == 2
|
||||
assert result[0].media_group_id is not None
|
||||
assert result[0].caption_entities[0].type == 'bold'
|
||||
assert result[1].caption_entities[0].type == 'italic'
|
||||
|
||||
def test_send_document_formating_caption(self):
|
||||
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ret_msg = tb.send_document(CHAT_ID, file_data, caption='_italic_', parse_mode='Markdown')
|
||||
assert ret_msg.caption_entities[0].type == 'italic'
|
||||
|
@ -6,19 +6,19 @@ from telebot import types
|
||||
|
||||
|
||||
def test_json_user():
|
||||
jsonstring = r'{"id":101176298,"first_name":"RDSSBOT","username":"rdss_bot"}'
|
||||
jsonstring = r'{"id":101176298,"first_name":"RDSSBOT","username":"rdss_bot","is_bot":true}'
|
||||
u = types.User.de_json(jsonstring)
|
||||
assert u.id == 101176298
|
||||
|
||||
|
||||
def test_json_message():
|
||||
jsonstring = r'{"message_id":1,"from":{"id":108929734,"first_name":"Frank","last_name":"Wang","username":"eternnoir"},"chat":{"id":1734,"first_name":"F","type":"private","last_name":"Wa","username":"oir"},"date":1435296025,"text":"HIHI"}'
|
||||
jsonstring = r'{"message_id":1,"from":{"id":108929734,"first_name":"Frank","last_name":"Wang","username":"eternnoir","is_bot":true},"chat":{"id":1734,"first_name":"F","type":"private","last_name":"Wa","username":"oir"},"date":1435296025,"text":"HIHI"}'
|
||||
msg = types.Message.de_json(jsonstring)
|
||||
assert msg.text == 'HIHI'
|
||||
|
||||
|
||||
def test_json_message_group():
|
||||
json_string = r'{"message_id":10,"from":{"id":12345,"first_name":"g","last_name":"G","username":"GG"},"chat":{"id":-866,"type":"private","title":"\u4ea4"},"date":1435303157,"text":"HIHI"}'
|
||||
json_string = r'{"message_id":10,"from":{"id":12345,"first_name":"g","last_name":"G","username":"GG","is_bot":true},"chat":{"id":-866,"type":"private","title":"\u4ea4"},"date":1435303157,"text":"HIHI"}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.text == 'HIHI'
|
||||
assert len(msg.chat.title) != 0
|
||||
@ -39,7 +39,7 @@ def test_json_Document():
|
||||
|
||||
|
||||
def test_json_Message_Audio():
|
||||
json_string = r'{"message_id":131,"from":{"id":12775,"first_name":"dd","username":"dd"},"chat":{"id":10834,"first_name":"dd","type":"private","type":"private","last_name":"dd","username":"dd"},"date":1439978364,"audio":{"duration":1,"mime_type":"audio\/mpeg","title":"pyTelegram","performer":"eternnoir","file_id":"BQADBQADDH1JaB8-1KyWUss2-Ag","file_size":20096}}'
|
||||
json_string = r'{"message_id":131,"from":{"id":12775,"first_name":"dd","username":"dd","is_bot":true },"chat":{"id":10834,"first_name":"dd","type":"private","type":"private","last_name":"dd","username":"dd"},"date":1439978364,"audio":{"duration":1,"mime_type":"audio\/mpeg","title":"pyTelegram","performer":"eternnoir","file_id":"BQADBQADDH1JaB8-1KyWUss2-Ag","file_size":20096}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.audio.duration == 1
|
||||
assert msg.content_type == 'audio'
|
||||
@ -48,7 +48,7 @@ def test_json_Message_Audio():
|
||||
|
||||
|
||||
def test_json_Message_Sticker():
|
||||
json_string = r'{"message_id":98,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435479551,"sticker":{"width":550,"height":368,"thumb":{"file_id":"AAQFABPJLB0sAAQq17w-li3bzoIfAAIC","file_size":1822,"width":90,"height":60},"file_id":"BQADBQADNAIAAsYifgYdGJOa6bGAsQI","file_size":30320}}'
|
||||
json_string = r'{"message_id":98,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435479551,"sticker":{"width":550,"height":368,"is_animated":true,"thumb":{"file_id":"AAQFABPJLB0sAAQq17w-li3bzoIfAAIC","file_size":1822,"width":90,"height":60},"file_id":"BQADBQADNAIAAsYifgYdGJOa6bGAsQI","file_size":30320}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.sticker.height == 368
|
||||
assert msg.sticker.thumb.height == 60
|
||||
@ -56,29 +56,29 @@ def test_json_Message_Sticker():
|
||||
|
||||
|
||||
def test_json_Message_Sticker_without_thumb():
|
||||
json_string = r'{"message_id":98,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435479551,"sticker":{"width":550,"height":368,"file_id":"BQADBQADNAIAAsYifgYdGJOa6bGAsQI","file_size":30320}}'
|
||||
json_string = r'{"message_id":98,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435479551,"sticker":{"width":550,"height":368,"is_animated":true,"file_id":"BQADBQADNAIAAsYifgYdGJOa6bGAsQI","file_size":30320}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.sticker.height == 368
|
||||
assert msg.sticker.thumb == None
|
||||
assert msg.sticker.thumb is None
|
||||
assert msg.content_type == 'sticker'
|
||||
|
||||
|
||||
def test_json_Message_Document():
|
||||
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_size":446}}'
|
||||
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_size":446}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.document.file_name == 'Text File'
|
||||
assert msg.content_type == 'document'
|
||||
|
||||
|
||||
def test_json_Message_Photo():
|
||||
json_string = r'{"message_id":96,"from":{"id":109734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"dd","username":"dd"},"date":1435478191,"photo":[{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":615,"width":90,"height":67},{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":10174,"width":320,"height":240},{"file_id":"dd-A_LsTIABFNx-FUOaEa_3AABAQABAg","file_size":53013,"width":759,"height":570}]}'
|
||||
json_string = r'{"message_id":96,"from":{"id":109734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"dd","username":"dd"},"date":1435478191,"photo":[{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":615,"width":90,"height":67},{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":10174,"width":320,"height":240},{"file_id":"dd-A_LsTIABFNx-FUOaEa_3AABAQABAg","file_size":53013,"width":759,"height":570}]}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert len(msg.photo) == 3
|
||||
assert msg.content_type == 'photo'
|
||||
|
||||
|
||||
def test_json_Message_Video():
|
||||
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_size":260699}}'
|
||||
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_size":260699}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.video
|
||||
assert msg.video.duration == 3
|
||||
@ -87,7 +87,7 @@ def test_json_Message_Video():
|
||||
|
||||
|
||||
def test_json_Message_Location():
|
||||
json_string = r'{"message_id":102,"from":{"id":108734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":1089734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1535482469,"location":{"longitude":127.479471,"latitude":26.090577}}'
|
||||
json_string = r'{"message_id":102,"from":{"id":108734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":1089734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1535482469,"location":{"longitude":127.479471,"latitude":26.090577}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.location.latitude == 26.090577
|
||||
assert msg.content_type == 'location'
|
||||
@ -113,13 +113,15 @@ def test_json_voice():
|
||||
assert voice.duration == 0
|
||||
assert voice.file_size == 10481
|
||||
|
||||
|
||||
def test_json_update():
|
||||
json_string = r'{"update_id":938203,"message":{"message_id":241,"from":{"id":9734,"first_name":"Fk","last_name":"Wg","username":"nir"},"chat":{"id":1111,"first_name":"Fk","type":"private","last_name":"Wg","username":"oir"},"date":1441447009,"text":"HIHI"}}'
|
||||
json_string = r'{"update_id":938203,"message":{"message_id":241,"from":{"is_bot":true,"id":9734,"first_name":"Fk","last_name":"Wg","username":"nir"},"chat":{"id":1111,"first_name":"Fk","type":"private","last_name":"Wg","username":"oir"},"date":1441447009,"text":"HIHI"}}'
|
||||
update = types.Update.de_json(json_string)
|
||||
assert update.update_id == 938203
|
||||
assert update.message.message_id == 241
|
||||
assert update.message.from_user.id == 9734
|
||||
|
||||
|
||||
def test_json_chat():
|
||||
json_string = r'{"id": -111111,"title": "Test Title","type": "group"}'
|
||||
chat = types.Chat.de_json(json_string)
|
||||
@ -127,6 +129,7 @@ def test_json_chat():
|
||||
assert chat.type == 'group'
|
||||
assert chat.title == 'Test Title'
|
||||
|
||||
|
||||
def test_InlineQueryResultCachedPhoto():
|
||||
iq = types.InlineQueryResultCachedPhoto('aaa', 'Fileid')
|
||||
json_str = iq.to_json()
|
||||
@ -143,6 +146,7 @@ def test_InlineQueryResultCachedPhoto_with_title():
|
||||
assert 'Title' in json_str
|
||||
assert 'caption' not in json_str
|
||||
|
||||
|
||||
def test_InlineQueryResultCachedPhoto_with_markup():
|
||||
markup = types.InlineKeyboardMarkup()
|
||||
markup.add(types.InlineKeyboardButton("Google", url="http://www.google.com"))
|
||||
@ -154,4 +158,3 @@ def test_InlineQueryResultCachedPhoto_with_markup():
|
||||
assert 'Title' in json_str
|
||||
assert 'caption' not in json_str
|
||||
assert 'reply_markup' in json_str
|
||||
|
||||
|
Reference in New Issue
Block a user