mirror of
https://github.com/eternnoir/pyTelegramBotAPI.git
synced 2023-08-10 21:12:57 +03:00
Compare commits
224 Commits
Author | SHA1 | Date | |
---|---|---|---|
e9f925e14c | |||
0304e6507f | |||
0f387db8d2 | |||
30664f396a | |||
cdffeba829 | |||
8e82d1c462 | |||
b5a4276282 | |||
d43292e42b | |||
99de5490a0 | |||
53ccef5e5e | |||
29b432e65a | |||
4f4c0891d9 | |||
03b1531bd7 | |||
ab496f995e | |||
44872ce87d | |||
c24d1e2d0b | |||
38694a9173 | |||
1494946d02 | |||
5facf7de92 | |||
f7008d4d99 | |||
32dc03ec44 | |||
dbff7cbb3e | |||
27e2cbc7ea | |||
592dcbfedf | |||
03b02561a5 | |||
783fe56566 | |||
2368421332 | |||
046276b491 | |||
3de8140c0b | |||
e5ad9ab383 | |||
d04e708438 | |||
200c6ccd07 | |||
75a018e18b | |||
aacc494a55 | |||
ee00d0458d | |||
a60253bf60 | |||
a80927baf9 | |||
8be9bcc8ed | |||
1824637617 | |||
df640966c2 | |||
2849e67029 | |||
d02de07142 | |||
a56fb8cc54 | |||
c5e5af96d1 | |||
5d388f7ec4 | |||
6c45511605 | |||
d8a08638a7 | |||
e2d70da694 | |||
6e1cf24946 | |||
be0fe94ee8 | |||
ef81868ebc | |||
57fb8d2fad | |||
c2590ab5ed | |||
24deb8a51d | |||
d7ebaa5bb3 | |||
601b570b85 | |||
bdaabc4752 | |||
72d088940c | |||
f1a960c56b | |||
bcc3a1afb4 | |||
d0edf44774 | |||
9c87ed3679 | |||
67cfa04737 | |||
be5d7bb73d | |||
f3a65ef9b3 | |||
99c63e9eba | |||
e89a552e06 | |||
bb4f6a7190 | |||
197dd2a582 | |||
dc3df70f9f | |||
aac9ce45a3 | |||
24e984adf8 | |||
1ed3bc2a53 | |||
ce11b6f523 | |||
8c7c7b31b2 | |||
39e3be6673 | |||
b1b2726ef6 | |||
da924dbaeb | |||
7966def331 | |||
aab560b4ee | |||
646bbb8330 | |||
339a5c01c1 | |||
615402e4f8 | |||
51b1fb7695 | |||
0881e34381 | |||
3aec66bc0d | |||
e7e7c58133 | |||
003c5db37f | |||
286188f380 | |||
dd726b0759 | |||
1bd9f5187c | |||
68330c9a07 | |||
b912e4dbaf | |||
dab80d421b | |||
247fe6e947 | |||
995814d846 | |||
36a228da92 | |||
ec86182f62 | |||
2c385bf077 | |||
56cbc2ff93 | |||
932ac9477b | |||
1e242f2263 | |||
862f17c716 | |||
ed7cf30034 | |||
100f6d77f6 | |||
d2f9c51a5a | |||
12547efa08 | |||
9410a3d310 | |||
a4e5a09ab2 | |||
ebfba49a8f | |||
6e6420a331 | |||
7ca629dc10 | |||
3ecb7cef3b | |||
e789407774 | |||
8f32dec5dd | |||
c57cfa3949 | |||
dfac26706e | |||
385fa98bc6 | |||
d68e89fc9a | |||
6023bae728 | |||
b323a868f0 | |||
583021d114 | |||
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 | |||
36621bb22a | |||
99466017c5 | |||
feec1dde56 | |||
54eba946be | |||
65a272b901 | |||
6a4c7e731b | |||
8634e65249 | |||
27d442fabf | |||
d17d28a144 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -58,4 +58,7 @@ docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
testMain.py
|
||||
testMain.py
|
||||
|
||||
#VS Code
|
||||
.vscode/
|
||||
|
@ -1,12 +1,9 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.6"
|
||||
- "2.7"
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
- "3.5"
|
||||
- "3.6"
|
||||
- "pypy"
|
||||
- "3.7"
|
||||
- "3.8"
|
||||
- "pypy3"
|
||||
install: "pip install -r requirements.txt"
|
||||
script:
|
||||
|
106
README.md
106
README.md
@ -2,7 +2,8 @@
|
||||
|
||||
<p align="center">A simple, but extensible Python implementation for the <a href="https://core.telegram.org/bots/api">Telegram Bot API</a>.
|
||||
|
||||
[](https://pypi.python.org/pypi/pyTelegramBotAPI)
|
||||
[](https://pypi.python.org/pypi/pyTelegramBotAPI)
|
||||
[](https://pypi.python.org/pypi/pyTelegramBotAPI)
|
||||
[](https://travis-ci.org/eternnoir/pyTelegramBotAPI)
|
||||
|
||||
* [Getting started.](#getting-started)
|
||||
@ -15,6 +16,7 @@
|
||||
* [General use of the API](#general-use-of-the-api)
|
||||
* [Message handlers](#message-handlers)
|
||||
* [Callback Query handlers](#callback-query-handler)
|
||||
* [Middleware handlers](#middleware-handler)
|
||||
* [TeleBot](#telebot)
|
||||
* [Reply markup](#reply-markup)
|
||||
* [Inline Mode](#inline-mode)
|
||||
@ -26,6 +28,8 @@
|
||||
* [Using web hooks](#using-web-hooks)
|
||||
* [Logging](#logging)
|
||||
* [Proxy](#proxy)
|
||||
* [API conformance](#api-conformance)
|
||||
* [Change log](#change-log)
|
||||
* [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)
|
||||
@ -154,7 +158,7 @@ TeleBot supports the following filters:
|
||||
|name|argument(s)|Condition|
|
||||
|:---:|---| ---|
|
||||
|content_types|list of strings (default `['text']`)|`True` if message.content_type is in the list of strings.|
|
||||
|regexp|a regular expression as a string|`True` if `re.search(regexp_arg)` returns `True` and `message.content_type == 'text'` (See [Python Regular Expressions](https://docs.python.org/2/library/re.html)|
|
||||
|regexp|a regular expression as a string|`True` if `re.search(regexp_arg)` returns `True` and `message.content_type == 'text'` (See [Python Regular Expressions](https://docs.python.org/2/library/re.html))|
|
||||
|commands|list of strings|`True` if `message.content_type == 'text'` and `message.text` starts with a command that is in the list of strings.|
|
||||
|func|a function (lambda or function reference)|`True` if the lambda or function reference returns `True`
|
||||
|
||||
@ -179,17 +183,17 @@ def handle_docs_audio(message):
|
||||
def handle_message(message):
|
||||
pass
|
||||
|
||||
#Handles all messages for which the lambda returns True
|
||||
# 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:
|
||||
# Which could also be defined as:
|
||||
def test_message(message):
|
||||
return message.document.mime_type == 'text/plain'
|
||||
|
||||
@bot.message_handler(func=test_message, content_types=['document'])
|
||||
def handle_text_doc(message)
|
||||
def handle_text_doc(message):
|
||||
pass
|
||||
|
||||
# Handlers can be stacked to create a function which will be called if either message_handler is eligible
|
||||
@ -203,25 +207,43 @@ def send_something(message):
|
||||
|
||||
#### Edited Message handlers
|
||||
|
||||
Same as Message handlers
|
||||
@bot.edited_message_handler(filters)
|
||||
|
||||
#### channel_post_handler
|
||||
|
||||
Same as Message handlers
|
||||
@bot.channel_post_handler(filters)
|
||||
|
||||
#### edited_channel_post_handler
|
||||
|
||||
Same as Message handlers
|
||||
@bot.edited_channel_post_handler(filters)
|
||||
|
||||
#### 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.
|
||||
In bot2.0 update. You can get `callback_query` in update object. In telebot use `callback_query_handler` to process callback queries.
|
||||
|
||||
```python
|
||||
@bot.callback_query_handler(func=lambda call: True)
|
||||
def test_callback(call):
|
||||
logger.info(call)
|
||||
```
|
||||
#### Middleware Handler
|
||||
|
||||
A middleware handler is a function that allows you to modify requests or the bot context as they pass through the
|
||||
Telegram to the bot. You can imagine middleware as a chain of logic connection handled before any other handlers are
|
||||
executed.
|
||||
|
||||
```python
|
||||
@bot.middleware_handler(update_types=['message'])
|
||||
def modify_message(bot_instance, message):
|
||||
# modifying the message before it reaches any other handler
|
||||
message.another_text = message.text + ':changed'
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
# the message is already modified when it reaches message handler
|
||||
assert message.another_text == message.text + ':changed'
|
||||
```
|
||||
There are other examples using middleware handler in the [examples/middleware](examples/middleware) directory.
|
||||
|
||||
#### TeleBot
|
||||
```python
|
||||
@ -250,7 +272,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)
|
||||
@ -371,7 +393,7 @@ 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.
|
||||
Now, you can use inline_handler to get inline queries in telebot.
|
||||
|
||||
```python
|
||||
|
||||
@ -465,7 +487,10 @@ The TeleBot constructor takes the following optional arguments:
|
||||
TeleBot should execute message handlers on it's polling Thread.
|
||||
|
||||
### The listener mechanism
|
||||
As an alternative to the message handlers, one can also register a function as a listener to TeleBot. Example:
|
||||
As an alternative to the message handlers, one can also register a function as a listener to TeleBot.
|
||||
|
||||
NOTICE: handlers won't disappear! Your message will be processed both by handlers and listeners. Also, it's impossible to predict which will work at first because of threading. If you use threaded=False, custom listeners will work earlier, after them handlers will be called.
|
||||
Example:
|
||||
```python
|
||||
def handle_messages(messages):
|
||||
for message in messages:
|
||||
@ -510,6 +535,33 @@ apihelper.proxy = {'https':'socks5://userproxy:password@proxy_address:port'}
|
||||
```
|
||||
|
||||
|
||||
## API conformance
|
||||
|
||||
_Checking is in progress..._
|
||||
|
||||
✅ [Bot API 3.5](https://core.telegram.org/bots/api-changelog#november-17-2017) _- To be checked..._
|
||||
|
||||
* ✔ [Bot API 3.4](https://core.telegram.org/bots/api-changelog#october-11-2017)
|
||||
* ✔ [Bot API 3.3](https://core.telegram.org/bots/api-changelog#august-23-2017)
|
||||
* ✔ [Bot API 3.2](https://core.telegram.org/bots/api-changelog#july-21-2017)
|
||||
* ✔ [Bot API 3.1](https://core.telegram.org/bots/api-changelog#june-30-2017)
|
||||
* ✔ [Bot API 3.0](https://core.telegram.org/bots/api-changelog#may-18-2017)
|
||||
* ✔ [Bot API 2.3.1](https://core.telegram.org/bots/api-changelog#december-4-2016)
|
||||
* ✔ [Bot API 2.3](https://core.telegram.org/bots/api-changelog#november-21-2016)
|
||||
* ✔ [Bot API 2.2](https://core.telegram.org/bots/api-changelog#october-3-2016)
|
||||
* ✔ [Bot API 2.1](https://core.telegram.org/bots/api-changelog#may-22-2016)
|
||||
* ✔ [Bot API 2.0](https://core.telegram.org/bots/api-changelog#april-9-2016)
|
||||
|
||||
|
||||
## Change log
|
||||
|
||||
27.04.2020 - Poll and Dice are up to date.
|
||||
Python2 conformance is not checked any more due to EOL.
|
||||
|
||||
11.04.2020 - Refactoring. new_chat_member is out of support. Bugfix in html_text. Started Bot API conformance checking.
|
||||
|
||||
06.06.2019 - Added polls support (Poll). Added functions send_poll, stop_poll
|
||||
|
||||
## F.A.Q.
|
||||
|
||||
### Bot 2.0
|
||||
@ -524,16 +576,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
|
||||
|
||||
```
|
||||
@ -561,7 +613,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.
|
||||
@ -576,16 +628,28 @@ 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.
|
||||
* [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.
|
||||
* [MusicQuiz_bot](https://t.me/MusicQuiz_bot) by [Etoneja](https://github.com/Etoneja) - Listen to audio samples 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.
|
||||
* [InfoBot](https://t.me/info2019_bot) ([source](https://github.com/irevenko/info-bot)) by @irevenko - An all-round bot that displays some statistics (weather, time, crypto etc...)
|
||||
* [FoodBot](https://t.me/ChensonUz_bot) ([source](https://github.com/Fliego/old_restaurant_telegram_chatbot)) by @Fliego - a simple bot for food ordering
|
||||
* [Sporty](https://t.me/SportydBot) ([source](https://github.com/0xnu/sporty)) by @0xnu - Telegram bot for displaying the latest news, sports schedules and injury updates.
|
||||
* [Neural style transfer](https://t.me/ebanyivolshebnikBot) ([source](https://github.com/timbyxty/StyleTransfer-tgbot)) by @timbyxty - bot for transferring style from one picture to another based on neural network.
|
||||
|
||||
Want to have your bot listed here? Send a Telegram message to @eternnoir or @pevdh.
|
||||
|
@ -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 telegram bot use pyTelegramBotAPI.
|
||||
import telebot
|
||||
import time
|
||||
import sys
|
||||
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)
|
||||
|
@ -9,8 +9,8 @@ bot = telebot.TeleBot(TELEGRAM_TOKEN)
|
||||
def gen_markup():
|
||||
markup = InlineKeyboardMarkup()
|
||||
markup.row_width = 2
|
||||
markup.add(InlineKeyboardButton("Yes", callback_data=f"cb_yes"),
|
||||
InlineKeyboardButton("No", callback_data=f"cb_no"))
|
||||
markup.add(InlineKeyboardButton("Yes", callback_data="cb_yes"),
|
||||
InlineKeyboardButton("No", callback_data="cb_no"))
|
||||
return markup
|
||||
|
||||
@bot.callback_query_handler(func=lambda call: True)
|
||||
|
53
examples/middleware/i18n.py
Normal file
53
examples/middleware/i18n.py
Normal file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# This example shows how to implement i18n (internationalization) l10n (localization) to create
|
||||
# multi-language bots with middleware handler.
|
||||
#
|
||||
# Note: For the sake of simplicity of this example no extra library is used. However, it is recommended to use
|
||||
# better i18n systems (gettext and etc) for handling multilingual translations.
|
||||
# This is not a working, production-ready sample and it is highly recommended not to use it in production.
|
||||
#
|
||||
# In this example let's imagine we want to introduce localization or internationalization into our project and
|
||||
# we need some global function to activate the language once and to use that language in all other message
|
||||
# handler functions for not repeatedly activating it.
|
||||
# The middleware (i18n and l10n) is explained:
|
||||
|
||||
import telebot
|
||||
from telebot import apihelper
|
||||
|
||||
apihelper.ENABLE_MIDDLEWARE = True
|
||||
|
||||
TRANSLATIONS = {
|
||||
'hello': {
|
||||
'en': 'hello',
|
||||
'ru': 'привет',
|
||||
'uz': 'salom'
|
||||
}
|
||||
}
|
||||
|
||||
_lang = 'en'
|
||||
|
||||
|
||||
def activate(lang):
|
||||
global _lang
|
||||
_lang = lang
|
||||
|
||||
|
||||
def _(string):
|
||||
return TRANSLATIONS[string][_lang]
|
||||
|
||||
|
||||
bot = telebot.TeleBot('TOKEN')
|
||||
|
||||
|
||||
@bot.middleware_handler(update_types=['message'])
|
||||
def activate_language(bot_instance, message):
|
||||
activate(message.from_user.language_code)
|
||||
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
bot.send_message(message.chat.id, _('hello'))
|
||||
|
||||
|
||||
bot.polling()
|
61
examples/middleware/session.py
Normal file
61
examples/middleware/session.py
Normal file
@ -0,0 +1,61 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# This example shows how to implement session creation and retrieval based on user id with middleware handler.
|
||||
#
|
||||
# Note: For the sake of simplicity of this example no extra library is used. However, it is recommended to use
|
||||
# in-memory or on-disk storage implementations (redis, mysql, postgres and etc) for storing and retrieving structures.
|
||||
# This is not a working, production-ready sample and it is highly recommended not to use it in production.
|
||||
#
|
||||
# In this example let's imagine we want to create a session for each user who communicates with the bot to store
|
||||
# different kind of temporary data while session is active. As an example we want to track the state of the user
|
||||
# with the help of this session. So, we need a way to store this session data somewhere globally to enable other
|
||||
# message handler functions to be able to use it.
|
||||
# The middleware session is explained:
|
||||
|
||||
import telebot
|
||||
from telebot import apihelper
|
||||
|
||||
apihelper.ENABLE_MIDDLEWARE = True
|
||||
|
||||
INFO_STATE = 'ON_INFO_MENU'
|
||||
MAIN_STATE = 'ON_MAIN_MENU'
|
||||
|
||||
SESSIONS = {
|
||||
-10000: {
|
||||
'state': INFO_STATE
|
||||
},
|
||||
-11111: {
|
||||
'state': MAIN_STATE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def get_or_create_session(user_id):
|
||||
try:
|
||||
return SESSIONS[user_id]
|
||||
except KeyError:
|
||||
SESSIONS[user_id] = {'state': MAIN_STATE}
|
||||
return SESSIONS[user_id]
|
||||
|
||||
|
||||
bot = telebot.TeleBot('TOKEN')
|
||||
|
||||
|
||||
@bot.middleware_handler(update_types=['message'])
|
||||
def set_session(bot_instance, message):
|
||||
bot_instance.session = get_or_create_session(message.from_user.id)
|
||||
|
||||
|
||||
@bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
bot.session['state'] = MAIN_STATE
|
||||
bot.send_message(message.chat.id, bot.session['state'])
|
||||
|
||||
|
||||
@bot.message_handler(commands=['info'])
|
||||
def start(message):
|
||||
bot.session['state'] = INFO_STATE
|
||||
bot.send_message(message.chat.id, bot.session['state'])
|
||||
|
||||
|
||||
bot.polling()
|
@ -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
|
||||
@ -84,5 +83,4 @@ bot.enable_save_next_step_handlers(delay=2)
|
||||
# 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,11 +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>'
|
||||
|
||||
@ -30,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)
|
||||
|
||||
@ -77,7 +77,7 @@ 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,8 +1,9 @@
|
||||
import os
|
||||
|
||||
import telebot
|
||||
from flask import Flask, request
|
||||
|
||||
import telebot
|
||||
|
||||
TOKEN = '<api_token>'
|
||||
bot = telebot.TeleBot(TOKEN)
|
||||
server = Flask(__name__)
|
||||
|
@ -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
|
||||
|
6
setup.py
6
setup.py
@ -7,7 +7,7 @@ def read(filename):
|
||||
return file.read()
|
||||
|
||||
setup(name='pyTelegramBotAPI',
|
||||
version='3.6.6',
|
||||
version='3.7.1',
|
||||
description='Python Telegram bot api. ',
|
||||
long_description=read('README.md'),
|
||||
long_description_content_type="text/markdown",
|
||||
@ -20,12 +20,10 @@ setup(name='pyTelegramBotAPI',
|
||||
install_requires=['requests', 'six'],
|
||||
extras_require={
|
||||
'json': 'ujson',
|
||||
'redis': 'redis>=3.4.1'
|
||||
},
|
||||
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',
|
||||
'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,20 +18,26 @@ from telebot import types
|
||||
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}"
|
||||
proxy = None
|
||||
session = None
|
||||
|
||||
API_URL = None
|
||||
FILE_URL = None
|
||||
|
||||
CONNECT_TIMEOUT = 3.5
|
||||
READ_TIMEOUT = 9999
|
||||
|
||||
CUSTOM_SERIALIZER = None
|
||||
|
||||
ENABLE_MIDDLEWARE = False
|
||||
|
||||
|
||||
def _get_req_session(reset=False):
|
||||
return util.per_thread('req_session', lambda: requests.session(), reset)
|
||||
return util.per_thread('req_session', lambda: session if session else 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,17 +47,24 @@ 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
|
||||
if files and format_header_param:
|
||||
fields.format_header_param = _no_encode(format_header_param)
|
||||
if params:
|
||||
if 'timeout' in params: read_timeout = params['timeout'] + 10
|
||||
if 'connect-timeout' in params: connect_timeout = params['connect-timeout'] + 10
|
||||
result = _get_req_session().request(method, request_url, params=params, files=files,
|
||||
timeout=(connect_timeout, read_timeout), proxies=proxy)
|
||||
if 'timeout' in params:
|
||||
read_timeout = params.pop('timeout') + 10
|
||||
if 'connect-timeout' in params:
|
||||
connect_timeout = params.pop('connect-timeout') + 10
|
||||
result = _get_req_session().request(
|
||||
method, request_url, params=params, files=files,
|
||||
timeout=(connect_timeout, read_timeout), proxies=proxy)
|
||||
logger.debug("The server returned: '{0}'".format(result.text.encode('utf8')))
|
||||
return _check_result(method_name, result)['result']
|
||||
|
||||
@ -99,12 +112,18 @@ def get_file(token, file_id):
|
||||
|
||||
|
||||
def get_file_url(token, file_id):
|
||||
method_url = r'getFile'
|
||||
return FILE_URL.format(token, get_file(token, file_id).file_path)
|
||||
|
||||
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)
|
||||
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}]' \
|
||||
@ -113,8 +132,10 @@ def download_file(token, file_path):
|
||||
return result.content
|
||||
|
||||
|
||||
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):
|
||||
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, timeout=None):
|
||||
"""
|
||||
Use this method to send text messages. On success, the sent Message is returned.
|
||||
:param token:
|
||||
@ -123,11 +144,14 @@ 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:
|
||||
:param timeout:
|
||||
:return:
|
||||
"""
|
||||
method_url = r'sendMessage'
|
||||
payload = {'chat_id': str(chat_id), 'text': text}
|
||||
if disable_web_page_preview:
|
||||
if disable_web_page_preview is not None:
|
||||
payload['disable_web_page_preview'] = disable_web_page_preview
|
||||
if reply_to_message_id:
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
@ -135,8 +159,10 @@ def send_message(token, chat_id, text, disable_web_page_preview=None, reply_to_m
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if parse_mode:
|
||||
payload['parse_mode'] = parse_mode
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
@ -232,16 +258,41 @@ def get_chat_member(token, chat_id, user_id):
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def forward_message(token, chat_id, from_chat_id, message_id, disable_notification=None):
|
||||
def forward_message(
|
||||
token, chat_id, from_chat_id, message_id,
|
||||
disable_notification=None, timeout=None):
|
||||
method_url = r'forwardMessage'
|
||||
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def send_photo(token, chat_id, photo, caption=None, reply_to_message_id=None, reply_markup=None,
|
||||
parse_mode=None, disable_notification=None):
|
||||
def send_dice(
|
||||
token, chat_id,
|
||||
emoji=None, disable_notification=None, reply_to_message_id=None,
|
||||
reply_markup=None, timeout=None):
|
||||
method_url = r'sendDice'
|
||||
payload = {'chat_id': chat_id}
|
||||
if emoji:
|
||||
payload['emoji'] = emoji
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
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 timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def send_photo(
|
||||
token, chat_id, photo,
|
||||
caption=None, reply_to_message_id=None, reply_markup=None,
|
||||
parse_mode=None, disable_notification=None, timeout=None):
|
||||
method_url = r'sendPhoto'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
@ -257,25 +308,36 @@ def send_photo(token, chat_id, photo, caption=None, reply_to_message_id=None, re
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if parse_mode:
|
||||
payload['parse_mode'] = parse_mode
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
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_media_group(token, chat_id, media, disable_notification=None, reply_to_message_id=None):
|
||||
def send_media_group(
|
||||
token, chat_id, media,
|
||||
disable_notification=None, reply_to_message_id=None,
|
||||
timeout=None):
|
||||
method_url = r'sendMediaGroup'
|
||||
media_json, files = _convert_input_media_array(media)
|
||||
payload = {'chat_id': chat_id, 'media': media_json}
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
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)
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
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):
|
||||
def send_location(
|
||||
token, chat_id, latitude, longitude,
|
||||
live_period=None, reply_to_message_id=None, reply_markup=None,
|
||||
disable_notification=None, timeout=None):
|
||||
method_url = r'sendLocation'
|
||||
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
|
||||
if live_period:
|
||||
@ -284,13 +346,15 @@ def send_location(token, chat_id, latitude, longitude, live_period=None, reply_t
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
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):
|
||||
inline_message_id=None, reply_markup=None, timeout=None):
|
||||
method_url = r'editMessageLiveLocation'
|
||||
payload = {'latitude': latitude, 'longitude': longitude}
|
||||
if chat_id:
|
||||
@ -301,11 +365,14 @@ def edit_message_live_location(token, latitude, longitude, chat_id=None, message
|
||||
payload['inline_message_id'] = inline_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
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):
|
||||
def stop_message_live_location(
|
||||
token, chat_id=None, message_id=None,
|
||||
inline_message_id=None, reply_markup=None, timeout=None):
|
||||
method_url = r'stopMessageLiveLocation'
|
||||
payload = {}
|
||||
if chat_id:
|
||||
@ -316,47 +383,59 @@ def stop_message_live_location(token, chat_id=None, message_id=None,
|
||||
payload['inline_message_id'] = inline_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
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):
|
||||
def send_venue(
|
||||
token, chat_id, latitude, longitude, title, address,
|
||||
foursquare_id=None, disable_notification=None,
|
||||
reply_to_message_id=None, reply_markup=None, timeout=None):
|
||||
method_url = r'sendVenue'
|
||||
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address}
|
||||
if foursquare_id:
|
||||
payload['foursquare_id'] = foursquare_id
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
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 timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def send_contact(token, chat_id, phone_number, first_name, last_name=None, disable_notification=None,
|
||||
reply_to_message_id=None, reply_markup=None):
|
||||
def send_contact(
|
||||
token, chat_id, phone_number, first_name,
|
||||
last_name=None, disable_notification=None,
|
||||
reply_to_message_id=None, reply_markup=None, timeout=None):
|
||||
method_url = r'sendContact'
|
||||
payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name}
|
||||
if last_name:
|
||||
payload['last_name'] = last_name
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
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 timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def send_chat_action(token, chat_id, action):
|
||||
def send_chat_action(token, chat_id, action, timeout=None):
|
||||
method_url = r'sendChatAction'
|
||||
payload = {'chat_id': chat_id, 'action': action}
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
|
||||
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None):
|
||||
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None, thumb=None):
|
||||
method_url = r'sendVideo'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
@ -374,9 +453,40 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if parse_mode:
|
||||
payload['parse_mode'] = parse_mode
|
||||
if supports_streaming:
|
||||
if supports_streaming is not None:
|
||||
payload['supports_streaming'] = supports_streaming
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
if thumb:
|
||||
if not util.is_string(thumb):
|
||||
files['thumb'] = thumb
|
||||
else:
|
||||
payload['thumb'] = thumb
|
||||
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 is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
@ -402,7 +512,7 @@ def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_mess
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if parse_mode:
|
||||
payload['parse_mode'] = parse_mode
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
@ -428,7 +538,7 @@ def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_m
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
if reply_markup:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
@ -436,7 +546,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, parse_mode=None, disable_notification=None, timeout=None):
|
||||
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None):
|
||||
method_url = r'sendAudio'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
@ -458,10 +568,15 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if parse_mode:
|
||||
payload['parse_mode'] = parse_mode
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
if thumb:
|
||||
if not util.is_string(thumb):
|
||||
files['thumb'] = thumb
|
||||
else:
|
||||
payload['thumb'] = thumb
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
@ -480,7 +595,7 @@ def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_m
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if parse_mode and data_type == 'document':
|
||||
payload['parse_mode'] = parse_mode
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
@ -510,49 +625,77 @@ def unban_chat_member(token, chat_id, user_id):
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def restrict_chat_member(token, chat_id, user_id, until_date=None, can_send_messages=None,
|
||||
can_send_media_messages=None, can_send_other_messages=None,
|
||||
can_add_web_page_previews=None):
|
||||
def restrict_chat_member(
|
||||
token, chat_id, user_id, until_date=None,
|
||||
can_send_messages=None, can_send_media_messages=None,
|
||||
can_send_polls=None, can_send_other_messages=None,
|
||||
can_add_web_page_previews=None, can_change_info=None,
|
||||
can_invite_users=None, can_pin_messages=None):
|
||||
method_url = 'restrictChatMember'
|
||||
payload = {'chat_id': chat_id, 'user_id': user_id}
|
||||
if until_date:
|
||||
if until_date is not None:
|
||||
payload['until_date'] = until_date
|
||||
if can_send_messages:
|
||||
if can_send_messages is not None:
|
||||
payload['can_send_messages'] = can_send_messages
|
||||
if can_send_media_messages:
|
||||
if can_send_media_messages is not None:
|
||||
payload['can_send_media_messages'] = can_send_media_messages
|
||||
if can_send_other_messages:
|
||||
if can_send_polls is not None:
|
||||
payload['can_send_polls'] = can_send_polls
|
||||
if can_send_other_messages is not None:
|
||||
payload['can_send_other_messages'] = can_send_other_messages
|
||||
if can_add_web_page_previews:
|
||||
if can_add_web_page_previews is not None:
|
||||
payload['can_add_web_page_previews'] = can_add_web_page_previews
|
||||
|
||||
if can_change_info is not None:
|
||||
payload['can_change_info'] = can_change_info
|
||||
if can_invite_users is not None:
|
||||
payload['can_invite_users'] = can_invite_users
|
||||
if can_pin_messages is not None:
|
||||
payload['can_pin_messages'] = can_pin_messages
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def promote_chat_member(token, chat_id, user_id, can_change_info=None, can_post_messages=None,
|
||||
can_edit_messages=None, can_delete_messages=None, can_invite_users=None,
|
||||
can_restrict_members=None, can_pin_messages=None, can_promote_members=None):
|
||||
def promote_chat_member(
|
||||
token, chat_id, user_id, can_change_info=None, can_post_messages=None,
|
||||
can_edit_messages=None, can_delete_messages=None, can_invite_users=None,
|
||||
can_restrict_members=None, can_pin_messages=None, can_promote_members=None):
|
||||
method_url = 'promoteChatMember'
|
||||
payload = {'chat_id': chat_id, 'user_id': user_id}
|
||||
if can_change_info:
|
||||
if can_change_info is not None:
|
||||
payload['can_change_info'] = can_change_info
|
||||
if can_post_messages:
|
||||
if can_post_messages is not None:
|
||||
payload['can_post_messages'] = can_post_messages
|
||||
if can_edit_messages:
|
||||
if can_edit_messages is not None:
|
||||
payload['can_edit_messages'] = can_edit_messages
|
||||
if can_delete_messages:
|
||||
if can_delete_messages is not None:
|
||||
payload['can_delete_messages'] = can_delete_messages
|
||||
if can_invite_users:
|
||||
if can_invite_users is not None:
|
||||
payload['can_invite_users'] = can_invite_users
|
||||
if can_restrict_members:
|
||||
if can_restrict_members is not None:
|
||||
payload['can_restrict_members'] = can_restrict_members
|
||||
if can_pin_messages:
|
||||
if can_pin_messages is not None:
|
||||
payload['can_pin_messages'] = can_pin_messages
|
||||
if can_promote_members:
|
||||
if can_promote_members is not None:
|
||||
payload['can_promote_members'] = can_promote_members
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def set_chat_administrator_custom_title(token, chat_id, user_id, custom_title):
|
||||
method_url = 'setChatAdministratorCustomTitle'
|
||||
payload = {
|
||||
'chat_id': chat_id, 'user_id': user_id, 'custom_title': custom_title
|
||||
}
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def set_chat_permissions(token, chat_id, permissions):
|
||||
method_url = 'setChatPermissions'
|
||||
payload = {
|
||||
'chat_id': chat_id,
|
||||
'permissions': permissions.to_json()
|
||||
}
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def export_chat_invite_link(token, chat_id):
|
||||
method_url = 'exportChatInviteLink'
|
||||
payload = {'chat_id': chat_id}
|
||||
@ -582,15 +725,23 @@ def set_chat_title(token, chat_id, title):
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def set_my_commands(token, commands):
|
||||
method_url = r'setMyCommands'
|
||||
payload = {'commands': _convert_list_json_serializable(commands)}
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def set_chat_description(token, chat_id, description):
|
||||
method_url = 'setChatDescription'
|
||||
payload = {'chat_id': chat_id, 'description': description}
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
def pin_chat_message(token, chat_id, message_id, disable_notification=False):
|
||||
def pin_chat_message(token, chat_id, message_id, disable_notification=None):
|
||||
method_url = 'pinChatMessage'
|
||||
payload = {'chat_id': chat_id, 'message_id': message_id, 'disable_notification': disable_notification}
|
||||
payload = {'chat_id': chat_id, 'message_id': message_id}
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
return _make_request(token, method_url, params=payload, method='post')
|
||||
|
||||
|
||||
@ -614,11 +765,11 @@ def edit_message_text(token, text, chat_id=None, message_id=None, inline_message
|
||||
payload['inline_message_id'] = inline_message_id
|
||||
if parse_mode:
|
||||
payload['parse_mode'] = parse_mode
|
||||
if disable_web_page_preview:
|
||||
if disable_web_page_preview is not None:
|
||||
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,
|
||||
@ -635,7 +786,7 @@ def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_m
|
||||
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):
|
||||
@ -664,26 +815,30 @@ 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
|
||||
|
||||
def send_game(token, chat_id, game_short_name, disable_notification=None, reply_to_message_id=None, reply_markup=None):
|
||||
def send_game(
|
||||
token, chat_id, game_short_name,
|
||||
disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None):
|
||||
method_url = r'sendGame'
|
||||
payload = {'chat_id': chat_id, 'game_short_name': game_short_name}
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
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 timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
@ -704,7 +859,7 @@ def set_game_score(token, user_id, score, force=None, disable_edit_message=None,
|
||||
"""
|
||||
method_url = r'setGameScore'
|
||||
payload = {'user_id': user_id, 'score': score}
|
||||
if force:
|
||||
if force is not None:
|
||||
payload['force'] = force
|
||||
if chat_id:
|
||||
payload['chat_id'] = chat_id
|
||||
@ -712,7 +867,7 @@ def set_game_score(token, user_id, score, force=None, disable_edit_message=None,
|
||||
payload['message_id'] = message_id
|
||||
if inline_message_id:
|
||||
payload['inline_message_id'] = inline_message_id
|
||||
if disable_edit_message:
|
||||
if disable_edit_message is not None:
|
||||
payload['disable_edit_message'] = disable_edit_message
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
@ -742,10 +897,12 @@ def get_game_high_scores(token, user_id, chat_id=None, message_id=None, inline_m
|
||||
|
||||
# Payments (https://core.telegram.org/bots/api#payments)
|
||||
|
||||
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, provider_data=None):
|
||||
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, provider_data=None,
|
||||
timeout=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)
|
||||
@ -769,7 +926,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,
|
||||
@ -783,17 +941,17 @@ def send_invoice(token, chat_id, title, description, invoice_payload, provider_t
|
||||
payload['photo_width'] = photo_width
|
||||
if photo_height:
|
||||
payload['photo_height'] = photo_height
|
||||
if need_name:
|
||||
if need_name is not None:
|
||||
payload['need_name'] = need_name
|
||||
if need_phone_number:
|
||||
if need_phone_number is not None:
|
||||
payload['need_phone_number'] = need_phone_number
|
||||
if need_email:
|
||||
if need_email is not None:
|
||||
payload['need_email'] = need_email
|
||||
if need_shipping_address:
|
||||
if need_shipping_address is not None:
|
||||
payload['need_shipping_address'] = need_shipping_address
|
||||
if is_flexible:
|
||||
if is_flexible is not None:
|
||||
payload['is_flexible'] = is_flexible
|
||||
if disable_notification:
|
||||
if disable_notification is not None:
|
||||
payload['disable_notification'] = disable_notification
|
||||
if reply_to_message_id:
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
@ -801,6 +959,8 @@ def send_invoice(token, chat_id, title, description, invoice_payload, provider_t
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if provider_data:
|
||||
payload['provider_data'] = provider_data
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
return _make_request(token, method_url, params=payload)
|
||||
|
||||
|
||||
@ -812,7 +972,7 @@ 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}
|
||||
@ -830,7 +990,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}
|
||||
@ -858,7 +1018,7 @@ def answer_callback_query(token, callback_query_id, text=None, show_alert=None,
|
||||
payload = {'callback_query_id': callback_query_id}
|
||||
if text:
|
||||
payload['text'] = text
|
||||
if show_alert:
|
||||
if show_alert is not None:
|
||||
payload['show_alert'] = show_alert
|
||||
if url:
|
||||
payload['url'] = url
|
||||
@ -873,7 +1033,7 @@ def answer_inline_query(token, inline_query_id, results, cache_time=None, is_per
|
||||
payload = {'inline_query_id': inline_query_id, 'results': _convert_list_json_serializable(results)}
|
||||
if cache_time is not None:
|
||||
payload['cache_time'] = cache_time
|
||||
if is_personal:
|
||||
if is_personal is not None:
|
||||
payload['is_personal'] = is_personal
|
||||
if next_offset is not None:
|
||||
payload['next_offset'] = next_offset
|
||||
@ -896,7 +1056,9 @@ def upload_sticker_file(token, user_id, png_sticker):
|
||||
return _make_request(token, method_url, params=payload, files=files, method='post')
|
||||
|
||||
|
||||
def create_new_sticker_set(token, user_id, name, title, png_sticker, emojis, contains_masks=None, mask_position=None):
|
||||
def create_new_sticker_set(
|
||||
token, user_id, name, title, png_sticker, emojis,
|
||||
contains_masks=None, mask_position=None):
|
||||
method_url = 'createNewStickerSet'
|
||||
payload = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis}
|
||||
files = None
|
||||
@ -904,7 +1066,7 @@ def create_new_sticker_set(token, user_id, name, title, png_sticker, emojis, con
|
||||
files = {'png_sticker': png_sticker}
|
||||
else:
|
||||
payload['png_sticker'] = png_sticker
|
||||
if contains_masks:
|
||||
if contains_masks is not None:
|
||||
payload['contains_masks'] = contains_masks
|
||||
if mask_position:
|
||||
payload['mask_position'] = mask_position.to_json()
|
||||
@ -936,6 +1098,56 @@ 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,
|
||||
is_anonymous = None, type = None, allows_multiple_answers = None, correct_option_id = None,
|
||||
explanation = None, explanation_parse_mode=None, open_period = None, close_date = None, is_closed = None,
|
||||
disable_notifications=False, reply_to_message_id=None, reply_markup=None, timeout=None):
|
||||
method_url = r'sendPoll'
|
||||
payload = {
|
||||
'chat_id': str(chat_id),
|
||||
'question': question,
|
||||
'options': json.dumps(options)}
|
||||
|
||||
if is_anonymous is not None:
|
||||
payload['is_anonymous'] = is_anonymous
|
||||
if type is not None:
|
||||
payload['type'] = type
|
||||
if allows_multiple_answers is not None:
|
||||
payload['allows_multiple_answers'] = allows_multiple_answers
|
||||
if correct_option_id is not None:
|
||||
payload['correct_option_id'] = correct_option_id
|
||||
if explanation is not None:
|
||||
payload['explanation'] = explanation
|
||||
if explanation_parse_mode is not None:
|
||||
payload['explanation_parse_mode'] = explanation_parse_mode
|
||||
if open_period is not None:
|
||||
payload['open_period'] = open_period
|
||||
if close_date is not None:
|
||||
payload['close_date'] = close_date
|
||||
if is_closed is not None:
|
||||
payload['is_closed'] = is_closed
|
||||
|
||||
if disable_notifications:
|
||||
payload['disable_notification'] = disable_notifications
|
||||
if reply_to_message_id is not None:
|
||||
payload['reply_to_message_id'] = reply_to_message_id
|
||||
if reply_markup is not None:
|
||||
payload['reply_markup'] = _convert_markup(reply_markup)
|
||||
if timeout:
|
||||
payload['connect-timeout'] = timeout
|
||||
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:
|
||||
@ -963,7 +1175,7 @@ def _convert_input_media_array(array):
|
||||
files = {}
|
||||
for input_media in array:
|
||||
if isinstance(input_media, types.InputMedia):
|
||||
media_dict = input_media.to_dic()
|
||||
media_dict = input_media.to_dict()
|
||||
if media_dict['media'].startswith('attach://'):
|
||||
key = media_dict['media'].replace('attach://', '')
|
||||
files[key] = input_media.media
|
||||
|
145
telebot/handler_backends.py
Normal file
145
telebot/handler_backends.py
Normal file
@ -0,0 +1,145 @@
|
||||
import os
|
||||
import pickle
|
||||
import threading
|
||||
|
||||
from telebot import apihelper
|
||||
|
||||
|
||||
class HandlerBackend(object):
|
||||
"""
|
||||
Class for saving (next step|reply) handlers
|
||||
"""
|
||||
def __init__(self, handlers=None):
|
||||
if handlers is None:
|
||||
handlers = {}
|
||||
self.handlers = handlers
|
||||
|
||||
def register_handler(self, handler_group_id, handler):
|
||||
raise NotImplementedError()
|
||||
|
||||
def clear_handlers(self, handler_group_id):
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_handlers(self, handler_group_id):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class MemoryHandlerBackend(HandlerBackend):
|
||||
def register_handler(self, handler_group_id, handler):
|
||||
if handler_group_id in self.handlers:
|
||||
self.handlers[handler_group_id].append(handler)
|
||||
else:
|
||||
self.handlers[handler_group_id] = [handler]
|
||||
|
||||
def clear_handlers(self, handler_group_id):
|
||||
self.handlers.pop(handler_group_id, [])
|
||||
|
||||
def get_handlers(self, handler_group_id):
|
||||
return self.handlers.pop(handler_group_id, [])
|
||||
|
||||
|
||||
class FileHandlerBackend(HandlerBackend):
|
||||
def __init__(self, handlers=None, filename='./.handler-saves/handlers.save', delay=120):
|
||||
super(FileHandlerBackend, self).__init__(handlers)
|
||||
self.filename = filename
|
||||
self.delay = delay
|
||||
self.timer = threading.Timer(delay, self.save_handlers)
|
||||
|
||||
def register_handler(self, handler_group_id, handler):
|
||||
if handler_group_id in self.handlers:
|
||||
self.handlers[handler_group_id].append(handler)
|
||||
else:
|
||||
self.handlers[handler_group_id] = [handler]
|
||||
|
||||
self.start_save_timer()
|
||||
|
||||
def clear_handlers(self, handler_group_id):
|
||||
self.handlers.pop(handler_group_id, [])
|
||||
|
||||
self.start_save_timer()
|
||||
|
||||
def get_handlers(self, handler_group_id):
|
||||
handlers = self.handlers.pop(handler_group_id, [])
|
||||
|
||||
self.start_save_timer()
|
||||
|
||||
return handlers
|
||||
|
||||
def start_save_timer(self):
|
||||
if not self.timer.is_alive():
|
||||
if self.delay <= 0:
|
||||
self.save_handlers()
|
||||
else:
|
||||
self.timer = threading.Timer(self.delay, self.save_handlers)
|
||||
self.timer.start()
|
||||
|
||||
def save_handlers(self):
|
||||
self.dump_handlers(self.handlers, self.filename)
|
||||
|
||||
def load_handlers(self, filename=None, del_file_after_loading=True):
|
||||
if not filename:
|
||||
filename = self.filename
|
||||
tmp = self.return_load_handlers(filename, del_file_after_loading=del_file_after_loading)
|
||||
if tmp is not None:
|
||||
self.handlers.update(tmp)
|
||||
|
||||
@staticmethod
|
||||
def dump_handlers(handlers, filename, file_mode="wb"):
|
||||
dirs = filename.rsplit('/', maxsplit=1)[0]
|
||||
os.makedirs(dirs, exist_ok=True)
|
||||
|
||||
with open(filename + ".tmp", file_mode) as file:
|
||||
if (apihelper.CUSTOM_SERIALIZER is None):
|
||||
pickle.dump(handlers, file)
|
||||
else:
|
||||
apihelper.CUSTOM_SERIALIZER.dump(handlers, file)
|
||||
|
||||
if os.path.isfile(filename):
|
||||
os.remove(filename)
|
||||
|
||||
os.rename(filename + ".tmp", filename)
|
||||
|
||||
@staticmethod
|
||||
def return_load_handlers(filename, del_file_after_loading=True):
|
||||
if os.path.isfile(filename) and os.path.getsize(filename) > 0:
|
||||
with open(filename, "rb") as file:
|
||||
if (apihelper.CUSTOM_SERIALIZER is None):
|
||||
handlers = pickle.load(file)
|
||||
else:
|
||||
handlers = apihelper.CUSTOM_SERIALIZER.load(file)
|
||||
|
||||
if del_file_after_loading:
|
||||
os.remove(filename)
|
||||
|
||||
return handlers
|
||||
|
||||
|
||||
class RedisHandlerBackend(HandlerBackend):
|
||||
def __init__(self, handlers=None, host='localhost', port=6379, db=0, prefix='telebot'):
|
||||
super(RedisHandlerBackend, self).__init__(handlers)
|
||||
from redis import Redis
|
||||
self.prefix = prefix
|
||||
self.redis = Redis(host, port, db)
|
||||
|
||||
def _key(self, handle_group_id):
|
||||
return ':'.join((self.prefix, str(handle_group_id)))
|
||||
|
||||
def register_handler(self, handler_group_id, handler):
|
||||
handlers = []
|
||||
value = self.redis.get(self._key(handler_group_id))
|
||||
if value:
|
||||
handlers = pickle.loads(value)
|
||||
handlers.append(handler)
|
||||
self.redis.set(self._key(handler_group_id), pickle.dumps(handlers))
|
||||
|
||||
def clear_handlers(self, handler_group_id):
|
||||
self.redis.delete(self._key(handler_group_id))
|
||||
|
||||
def get_handlers(self, handler_group_id):
|
||||
handlers = []
|
||||
value = self.redis.get(self._key(handler_group_id))
|
||||
if value:
|
||||
handlers = pickle.loads(value)
|
||||
self.clear_handlers(handler_group_id)
|
||||
|
||||
return handlers
|
895
telebot/types.py
895
telebot/types.py
File diff suppressed because it is too large
Load Diff
127
telebot/util.py
127
telebot/util.py
@ -1,10 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
import re
|
||||
import sys
|
||||
import warnings
|
||||
import functools
|
||||
|
||||
import six
|
||||
from six import string_types
|
||||
|
||||
@ -22,67 +25,67 @@ thread_local = threading.local()
|
||||
|
||||
|
||||
class WorkerThread(threading.Thread):
|
||||
count = 0
|
||||
count = 0
|
||||
|
||||
def __init__(self, exception_callback=None, queue=None, name=None):
|
||||
if not name:
|
||||
name = "WorkerThread{0}".format(self.__class__.count + 1)
|
||||
self.__class__.count += 1
|
||||
if not queue:
|
||||
queue = Queue.Queue()
|
||||
def __init__(self, exception_callback=None, queue=None, name=None):
|
||||
if not name:
|
||||
name = "WorkerThread{0}".format(self.__class__.count + 1)
|
||||
self.__class__.count += 1
|
||||
if not queue:
|
||||
queue = Queue.Queue()
|
||||
|
||||
threading.Thread.__init__(self, name=name)
|
||||
self.queue = queue
|
||||
self.daemon = True
|
||||
threading.Thread.__init__(self, name=name)
|
||||
self.queue = queue
|
||||
self.daemon = True
|
||||
|
||||
self.received_task_event = threading.Event()
|
||||
self.done_event = threading.Event()
|
||||
self.exception_event = threading.Event()
|
||||
self.continue_event = threading.Event()
|
||||
self.received_task_event = threading.Event()
|
||||
self.done_event = threading.Event()
|
||||
self.exception_event = threading.Event()
|
||||
self.continue_event = threading.Event()
|
||||
|
||||
self.exception_callback = exception_callback
|
||||
self.exc_info = None
|
||||
self._running = True
|
||||
self.start()
|
||||
self.exception_callback = exception_callback
|
||||
self.exc_info = None
|
||||
self._running = True
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
while self._running:
|
||||
try:
|
||||
task, args, kwargs = self.queue.get(block=True, timeout=.5)
|
||||
self.continue_event.clear()
|
||||
self.received_task_event.clear()
|
||||
self.done_event.clear()
|
||||
self.exception_event.clear()
|
||||
logger.debug("Received task")
|
||||
self.received_task_event.set()
|
||||
def run(self):
|
||||
while self._running:
|
||||
try:
|
||||
task, args, kwargs = self.queue.get(block=True, timeout=.5)
|
||||
self.continue_event.clear()
|
||||
self.received_task_event.clear()
|
||||
self.done_event.clear()
|
||||
self.exception_event.clear()
|
||||
logger.debug("Received task")
|
||||
self.received_task_event.set()
|
||||
|
||||
task(*args, **kwargs)
|
||||
logger.debug("Task complete")
|
||||
self.done_event.set()
|
||||
except Queue.Empty:
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.error(type(e).__name__ + " occurred, args=" + str(e.args) + "\n" + traceback.format_exc())
|
||||
self.exc_info = sys.exc_info()
|
||||
self.exception_event.set()
|
||||
task(*args, **kwargs)
|
||||
logger.debug("Task complete")
|
||||
self.done_event.set()
|
||||
except Queue.Empty:
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.error(type(e).__name__ + " occurred, args=" + str(e.args) + "\n" + traceback.format_exc())
|
||||
self.exc_info = sys.exc_info()
|
||||
self.exception_event.set()
|
||||
|
||||
if self.exception_callback:
|
||||
self.exception_callback(self, self.exc_info)
|
||||
self.continue_event.wait()
|
||||
if self.exception_callback:
|
||||
self.exception_callback(self, self.exc_info)
|
||||
self.continue_event.wait()
|
||||
|
||||
def put(self, task, *args, **kwargs):
|
||||
self.queue.put((task, args, kwargs))
|
||||
def put(self, task, *args, **kwargs):
|
||||
self.queue.put((task, args, kwargs))
|
||||
|
||||
def raise_exceptions(self):
|
||||
if self.exception_event.is_set():
|
||||
six.reraise(self.exc_info[0], self.exc_info[1], self.exc_info[2])
|
||||
def raise_exceptions(self):
|
||||
if self.exception_event.is_set():
|
||||
six.reraise(self.exc_info[0], self.exc_info[1], self.exc_info[2])
|
||||
|
||||
def clear_exceptions(self):
|
||||
self.exception_event.clear()
|
||||
self.continue_event.set()
|
||||
def clear_exceptions(self):
|
||||
self.exception_event.clear()
|
||||
self.continue_event.set()
|
||||
|
||||
def stop(self):
|
||||
self._running = False
|
||||
def stop(self):
|
||||
self._running = False
|
||||
|
||||
|
||||
class ThreadPool:
|
||||
@ -243,7 +246,7 @@ 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(r"/\w*(@\w*)*\s*([\s\S]*)",re.IGNORECASE)
|
||||
result = regexp.match(text)
|
||||
return result.group(2) if is_command(text) else None
|
||||
|
||||
@ -257,4 +260,20 @@ def per_thread(key, construct_value, reset=False):
|
||||
|
||||
|
||||
def generate_random_token():
|
||||
return ''.join(random.sample(string.ascii_letters, 16))
|
||||
return ''.join(random.sample(string.ascii_letters, 16))
|
||||
|
||||
|
||||
def deprecated(func):
|
||||
"""This is a decorator which can be used to mark functions
|
||||
as deprecated. It will result in a warning being emitted
|
||||
when the function is used."""
|
||||
# https://stackoverflow.com/a/30253848/441814
|
||||
@functools.wraps(func)
|
||||
def new_func(*args, **kwargs):
|
||||
warnings.simplefilter('always', DeprecationWarning) # turn off filter
|
||||
warnings.warn("Call to deprecated function {}.".format(func.__name__),
|
||||
category=DeprecationWarning,
|
||||
stacklevel=2)
|
||||
warnings.simplefilter('default', DeprecationWarning) # reset filter
|
||||
return func(*args, **kwargs)
|
||||
return new_func
|
||||
|
270
tests/test_handler_backends.py
Normal file
270
tests/test_handler_backends.py
Normal file
@ -0,0 +1,270 @@
|
||||
import sys
|
||||
|
||||
sys.path.append('../')
|
||||
|
||||
REDIS_TESTS = False
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
import telebot
|
||||
from telebot import types
|
||||
from telebot.handler_backends import MemoryHandlerBackend, FileHandlerBackend
|
||||
|
||||
if REDIS_TESTS:
|
||||
from telebot.handler_backends import RedisHandlerBackend
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def telegram_bot():
|
||||
return telebot.TeleBot('', threaded=False)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def private_chat():
|
||||
return types.Chat(id=11, type='private')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def user():
|
||||
return types.User(id=10, is_bot=False, first_name='Some User')
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def message(user, private_chat):
|
||||
params = {'text': '/start'}
|
||||
return types.Message(
|
||||
message_id=1, from_user=user, date=None, chat=private_chat, content_type='text', options=params, json_string=""
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def reply_to_message(user, private_chat, message):
|
||||
params = {'text': '/start'}
|
||||
reply_message = types.Message(
|
||||
message_id=2, from_user=user, date=None, chat=private_chat, content_type='text', options=params, json_string=""
|
||||
)
|
||||
reply_message.reply_to_message = message
|
||||
return reply_message
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def update_type(message):
|
||||
edited_message = None
|
||||
channel_post = None
|
||||
edited_channel_post = None
|
||||
inline_query = None
|
||||
chosen_inline_result = None
|
||||
callback_query = None
|
||||
shipping_query = None
|
||||
pre_checkout_query = None
|
||||
poll = None
|
||||
poll_answer = None
|
||||
return types.Update(1001234038283, message, edited_message, channel_post, edited_channel_post, inline_query,
|
||||
chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll, poll_answer)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def reply_to_message_update_type(reply_to_message):
|
||||
edited_message = None
|
||||
channel_post = None
|
||||
edited_channel_post = None
|
||||
inline_query = None
|
||||
chosen_inline_result = None
|
||||
callback_query = None
|
||||
shipping_query = None
|
||||
pre_checkout_query = None
|
||||
poll = None
|
||||
poll_answer = None
|
||||
return types.Update(1001234038284, reply_to_message, edited_message, channel_post, edited_channel_post,
|
||||
inline_query,
|
||||
chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll, poll_answer)
|
||||
|
||||
|
||||
def next_handler(message):
|
||||
message.text = 'entered next_handler'
|
||||
|
||||
|
||||
def test_memory_handler_backend_default_backend(telegram_bot):
|
||||
assert telegram_bot.reply_backend.__class__ == MemoryHandlerBackend
|
||||
assert telegram_bot.next_step_backend.__class__ == MemoryHandlerBackend
|
||||
|
||||
|
||||
def test_memory_handler_backend_register_next_step_handler(telegram_bot, private_chat, update_type):
|
||||
@telegram_bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
message.text = 'entered start'
|
||||
telegram_bot.register_next_step_handler_by_chat_id(message.chat.id, next_handler)
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered start'
|
||||
|
||||
assert len(telegram_bot.next_step_backend.handlers[private_chat.id]) == 1
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered next_handler'
|
||||
|
||||
assert private_chat.id not in telegram_bot.next_step_backend.handlers
|
||||
|
||||
|
||||
def test_memory_handler_backend_clear_next_step_handler(telegram_bot, private_chat, update_type):
|
||||
@telegram_bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
message.text = 'entered start'
|
||||
telegram_bot.register_next_step_handler_by_chat_id(message.chat.id, next_handler)
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered start'
|
||||
|
||||
assert len(telegram_bot.next_step_backend.handlers[private_chat.id]) == 1
|
||||
|
||||
telegram_bot.clear_step_handler_by_chat_id(private_chat.id)
|
||||
|
||||
assert private_chat.id not in telegram_bot.next_step_backend.handlers
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered start'
|
||||
|
||||
|
||||
def test_memory_handler_backend_register_reply_handler(telegram_bot, private_chat, update_type,
|
||||
reply_to_message_update_type):
|
||||
@telegram_bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
message.text = 'entered start'
|
||||
telegram_bot.register_for_reply_by_message_id(message.message_id, next_handler)
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered start'
|
||||
|
||||
assert len(telegram_bot.reply_backend.handlers[update_type.message.message_id]) == 1
|
||||
|
||||
telegram_bot.process_new_updates([reply_to_message_update_type])
|
||||
assert reply_to_message_update_type.message.text == 'entered next_handler'
|
||||
|
||||
assert private_chat.id not in telegram_bot.reply_backend.handlers
|
||||
|
||||
|
||||
def test_memory_handler_backend_clear_reply_handler(telegram_bot, private_chat, update_type,
|
||||
reply_to_message_update_type):
|
||||
@telegram_bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
message.text = 'entered start'
|
||||
telegram_bot.register_for_reply_by_message_id(message.message_id, next_handler)
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered start'
|
||||
|
||||
assert len(telegram_bot.reply_backend.handlers[update_type.message.message_id]) == 1
|
||||
|
||||
telegram_bot.clear_reply_handlers_by_message_id(update_type.message.message_id)
|
||||
|
||||
assert update_type.message.message_id not in telegram_bot.reply_backend.handlers
|
||||
|
||||
telegram_bot.process_new_updates([reply_to_message_update_type])
|
||||
assert reply_to_message_update_type.message.text == 'entered start'
|
||||
|
||||
|
||||
def test_file_handler_backend_register_next_step_handler(telegram_bot, private_chat, update_type):
|
||||
telegram_bot.next_step_backend=FileHandlerBackend(filename='./.handler-saves/step1.save', delay=0.1)
|
||||
|
||||
@telegram_bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
message.text = 'entered start'
|
||||
telegram_bot.register_next_step_handler_by_chat_id(message.chat.id, next_handler)
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered start'
|
||||
|
||||
time.sleep(0.2)
|
||||
|
||||
assert os.path.exists(telegram_bot.next_step_backend.filename)
|
||||
|
||||
assert len(telegram_bot.next_step_backend.handlers[private_chat.id]) == 1
|
||||
|
||||
telegram_bot.next_step_backend.handlers = {}
|
||||
|
||||
telegram_bot.next_step_backend.load_handlers()
|
||||
|
||||
assert len(telegram_bot.next_step_backend.handlers[private_chat.id]) == 1
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered next_handler'
|
||||
|
||||
assert private_chat.id not in telegram_bot.next_step_backend.handlers
|
||||
|
||||
time.sleep(0.2)
|
||||
if os.path.exists(telegram_bot.next_step_backend.filename):
|
||||
os.remove(telegram_bot.next_step_backend.filename)
|
||||
|
||||
|
||||
def test_file_handler_backend_clear_next_step_handler(telegram_bot, private_chat, update_type):
|
||||
telegram_bot.next_step_backend=FileHandlerBackend(filename='./.handler-saves/step2.save', delay=0.1)
|
||||
|
||||
@telegram_bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
message.text = 'entered start'
|
||||
telegram_bot.register_next_step_handler_by_chat_id(message.chat.id, next_handler)
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered start'
|
||||
|
||||
assert len(telegram_bot.next_step_backend.handlers[private_chat.id]) == 1
|
||||
|
||||
time.sleep(0.2)
|
||||
|
||||
assert os.path.exists(telegram_bot.next_step_backend.filename)
|
||||
|
||||
telegram_bot.clear_step_handler_by_chat_id(private_chat.id)
|
||||
|
||||
time.sleep(0.2)
|
||||
|
||||
telegram_bot.next_step_backend.load_handlers()
|
||||
|
||||
assert private_chat.id not in telegram_bot.next_step_backend.handlers
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered start'
|
||||
|
||||
time.sleep(0.2)
|
||||
if os.path.exists(telegram_bot.next_step_backend.filename):
|
||||
os.remove(telegram_bot.next_step_backend.filename)
|
||||
|
||||
|
||||
def test_redis_handler_backend_register_next_step_handler(telegram_bot, private_chat, update_type):
|
||||
if not REDIS_TESTS:
|
||||
pytest.skip('please install redis and configure redis server, then enable REDIS_TESTS')
|
||||
|
||||
telegram_bot.next_step_backend = RedisHandlerBackend(prefix='pyTelegramBotApi:step_backend1')
|
||||
|
||||
@telegram_bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
message.text = 'entered start'
|
||||
telegram_bot.register_next_step_handler_by_chat_id(message.chat.id, next_handler)
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered start'
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered next_handler'
|
||||
|
||||
|
||||
def test_redis_handler_backend_clear_next_step_handler(telegram_bot, private_chat, update_type):
|
||||
if not REDIS_TESTS:
|
||||
pytest.skip('please install redis and configure redis server, then enable REDIS_TESTS')
|
||||
|
||||
telegram_bot.next_step_backend = RedisHandlerBackend(prefix='pyTelegramBotApi:step_backend2')
|
||||
|
||||
@telegram_bot.message_handler(commands=['start'])
|
||||
def start(message):
|
||||
message.text = 'entered start'
|
||||
telegram_bot.register_next_step_handler_by_chat_id(message.chat.id, next_handler)
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered start'
|
||||
|
||||
telegram_bot.clear_step_handler_by_chat_id(private_chat.id)
|
||||
|
||||
telegram_bot.process_new_updates([update_type])
|
||||
assert update_type.message.text == 'entered start'
|
@ -48,7 +48,7 @@ class TestTeleBot:
|
||||
bot = telebot.TeleBot('')
|
||||
msg = self.create_text_message(r'https://web.telegram.org/')
|
||||
|
||||
@bot.message_handler(regexp='((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)')
|
||||
@bot.message_handler(regexp=r'((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)')
|
||||
def command_url(message):
|
||||
msg.text = 'got'
|
||||
|
||||
@ -84,7 +84,7 @@ class TestTeleBot:
|
||||
bot = telebot.TeleBot('')
|
||||
msg = self.create_text_message(r'web.telegram.org/')
|
||||
|
||||
@bot.message_handler(regexp='((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)')
|
||||
@bot.message_handler(regexp=r'((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)')
|
||||
def command_url(message):
|
||||
msg.text = 'got'
|
||||
|
||||
@ -241,6 +241,12 @@ class TestTeleBot:
|
||||
ret_msg = tb.send_message(CHAT_ID, text)
|
||||
assert ret_msg.message_id
|
||||
|
||||
def test_send_dice(self):
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ret_msg = tb.send_dice(CHAT_ID, emoji='🎯')
|
||||
assert ret_msg.message_id
|
||||
assert ret_msg.content_type == 'dice'
|
||||
|
||||
def test_send_message_dis_noti(self):
|
||||
text = 'CI Test Message'
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
@ -402,11 +408,30 @@ 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, False, 'test')
|
||||
return types.Message(1, None, None, chat, 'text', params, "")
|
||||
|
||||
@staticmethod
|
||||
def create_message_update(text):
|
||||
params = {'text': text}
|
||||
chat = types.User(11, False, 'test')
|
||||
message = types.Message(1, None, None, chat, 'text', params, "")
|
||||
edited_message = None
|
||||
channel_post = None
|
||||
edited_channel_post = None
|
||||
inline_query = None
|
||||
chosen_inline_result = None
|
||||
callback_query = None
|
||||
shipping_query = None
|
||||
pre_checkout_query = None
|
||||
poll = None
|
||||
poll_answer = None
|
||||
return types.Update(-1001234038283, message, edited_message, channel_post, edited_channel_post, inline_query,
|
||||
chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll, poll_answer)
|
||||
|
||||
def test_is_string_unicode(self):
|
||||
s1 = u'string'
|
||||
assert util.is_string(s1)
|
||||
@ -488,3 +513,49 @@ class TestTeleBot:
|
||||
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'
|
||||
|
||||
def test_typed_middleware_handler(self):
|
||||
from telebot import apihelper
|
||||
|
||||
apihelper.ENABLE_MIDDLEWARE = True
|
||||
|
||||
tb = telebot.TeleBot('')
|
||||
update = self.create_message_update('/help')
|
||||
|
||||
@tb.middleware_handler(update_types=['message'])
|
||||
def middleware(tb_instance, message):
|
||||
message.text = 'got'
|
||||
|
||||
@tb.message_handler(func=lambda m: m.text == 'got')
|
||||
def command_handler(message):
|
||||
message.text = message.text + message.text
|
||||
|
||||
tb.process_new_updates([update])
|
||||
time.sleep(1)
|
||||
assert update.message.text == 'got' * 2
|
||||
|
||||
def test_default_middleware_handler(self):
|
||||
from telebot import apihelper
|
||||
|
||||
apihelper.ENABLE_MIDDLEWARE = True
|
||||
|
||||
tb = telebot.TeleBot('')
|
||||
update = self.create_message_update('/help')
|
||||
|
||||
@tb.middleware_handler()
|
||||
def middleware(tb_instance, update):
|
||||
update.message.text = 'got'
|
||||
|
||||
@tb.message_handler(func=lambda m: m.text == 'got')
|
||||
def command_handler(message):
|
||||
message.text = message.text + message.text
|
||||
|
||||
tb.process_new_updates([update])
|
||||
time.sleep(1)
|
||||
assert update.message.text == 'got' * 2
|
||||
|
||||
def test_chat_permissions(self):
|
||||
return # CHAT_ID is private chat, no permissions can be set
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
permissions = types.ChatPermissions(can_send_messages=True, can_send_polls=False)
|
||||
msg = tb.set_chat_permissions(CHAT_ID, permissions)
|
||||
|
@ -17,6 +17,15 @@ def test_json_message():
|
||||
assert msg.text == 'HIHI'
|
||||
|
||||
|
||||
def test_json_message_with_dice():
|
||||
jsonstring = r'{"message_id":5560,"from":{"id":879343317,"is_bot":false,"first_name":"George","last_name":"Forse","username":"dr_fxrse","language_code":"ru"},"chat":{"id":879343317,"first_name":"George","last_name":"Forse","username":"dr_fxrse","type":"private"},"date":1586926330,"dice":{"value": 4, "emoji": "\ud83c\udfaf"}}'
|
||||
msg = types.Message.de_json(jsonstring)
|
||||
assert msg.content_type == 'dice'
|
||||
assert isinstance(msg.dice, types.Dice)
|
||||
assert msg.dice.value == 4
|
||||
assert msg.dice.emoji == '🎯'
|
||||
|
||||
|
||||
def test_json_message_group():
|
||||
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)
|
||||
@ -48,7 +57,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","is_bot":true },"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,10 +65,10 @@ 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","is_bot":true },"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'
|
||||
|
||||
|
||||
@ -113,6 +122,7 @@ 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":{"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)
|
||||
@ -120,6 +130,7 @@ def test_json_update():
|
||||
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 +138,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 +155,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"))
|
||||
@ -155,3 +168,31 @@ def test_InlineQueryResultCachedPhoto_with_markup():
|
||||
assert 'caption' not in json_str
|
||||
assert 'reply_markup' in json_str
|
||||
|
||||
|
||||
def test_json_poll_1():
|
||||
jsonstring = r'{"message_id": 395020,"from": {"id": 111,"is_bot": false,"first_name": "FN","last_name": "LN","username": "Badiboy","language_code": "ru"},"chat": {"id": 111,"first_name": "FN","last_name": "LN","username": "Badiboy","type": "private"},"date": 1587841239,"poll": {"id": "5272018969396510722","question": "Test poll 1","options": [{"text": "Answer 1","voter_count": 0},{"text": "Answer 2","voter_count": 0}],"total_voter_count": 0,"is_closed": false,"is_anonymous": true,"type": "regular","allows_multiple_answers": true}}'
|
||||
msg = types.Message.de_json(jsonstring)
|
||||
assert msg.poll is not None
|
||||
assert isinstance(msg.poll, types.Poll)
|
||||
assert msg.poll.id == '5272018969396510722'
|
||||
assert msg.poll.question is not None
|
||||
assert msg.poll.options is not None
|
||||
assert len(msg.poll.options) == 2
|
||||
assert msg.poll.allows_multiple_answers is True
|
||||
|
||||
|
||||
def test_json_poll_answer():
|
||||
jsonstring = r'{"poll_id": "5895675970559410186", "user": {"id": 329343347, "is_bot": false, "first_name": "Test", "username": "test_user", "last_name": "User", "language_code": "en"}, "option_ids": [1]}'
|
||||
__import__('pprint').pprint(__import__('json').loads(jsonstring))
|
||||
poll_answer = types.PollAnswer.de_json(jsonstring)
|
||||
assert poll_answer.poll_id == '5895675970559410186'
|
||||
assert isinstance(poll_answer.user, types.User)
|
||||
assert poll_answer.options_ids == [1]
|
||||
|
||||
|
||||
def test_KeyboardButtonPollType():
|
||||
markup = types.ReplyKeyboardMarkup()
|
||||
markup.add(types.KeyboardButton('send me a poll', request_poll=types.KeyboardButtonPollType(type='quiz')))
|
||||
json_str = markup.to_json()
|
||||
assert 'request_poll' in json_str
|
||||
assert 'quiz' in json_str
|
||||
|
Reference in New Issue
Block a user