1
0
mirror of https://github.com/eternnoir/pyTelegramBotAPI.git synced 2023-08-10 21:12:57 +03:00

Compare commits

...

568 Commits
0.2.0 ... 3.2.0

Author SHA1 Message Date
dcddedcd24 Fix file dic. 2017-08-06 15:35:43 +08:00
2e743b4b86 Add v3.2 method. 2017-08-06 15:22:23 +08:00
af70313721 New method for v3.2 2017-08-06 14:25:25 +08:00
aefd666062 Update sticker set. 2017-08-06 12:00:26 +08:00
23d66afbb0 Merge pull request #381 from noirgif/master
change the documentation of TeleBot.polling in readme
2017-08-01 09:31:01 +08:00
ed29f9316f change the documentation of TeleBot.polling in readme 2017-07-30 23:24:30 -07:00
c91ce6036b Merge pull request #372 from Kylmakalle/master
Async Methods for API v3.1
2017-07-23 15:50:02 +08:00
cb60a1256f Merge pull request #374 from the31k/per_thread_requests_sessions
Per-thread requests sessions
2017-07-23 15:49:42 +08:00
96569cbdac Fix typo 2017-07-19 15:44:10 +03:00
feec19b7f4 Use per-thread requests sessions
Reason is requests.Session is not thread-safe
See: https://github.com/requests/requests/issues/2766
2017-07-19 01:50:12 +03:00
1a80fc5a0e Per-thread singletons 2017-07-19 01:50:04 +03:00
488fb745b7 Merge pull request #359 from Yolley/master
Informative exception message for better exception handling
2017-07-07 10:45:23 +08:00
08d6ab549d Aync Methods for v3.1 2017-07-07 00:54:18 +03:00
f718c36ea7 Merge remote-tracking branch 'refs/remotes/eternnoir/master' 2017-07-07 00:29:40 +03:00
ed88939110 Merge remote-tracking branch 'refs/remotes/eternnoir/master' 2017-07-07 00:25:13 +03:00
0632cfb9b0 Fix new chat members. 2017-07-02 21:24:19 +08:00
4979589faf Fix not require args. #369 2017-07-02 21:08:36 +08:00
d2f694516a Update version. 2017-07-01 11:24:29 +08:00
5f8ed347a1 Add missing arg until_date for kickChatMember. 2017-07-01 11:11:25 +08:00
514880fe22 Merge remote-tracking branch 'origin/proxySupport' 2017-07-01 11:06:05 +08:00
f97bb2f615 FIx missing declare 2017-07-01 11:05:14 +08:00
38af4f441b Merge pull request #368 from MasterGroosha/botapi_v3.1
Bot API v3.1
2017-07-01 10:33:35 +08:00
662a834138 Added missing arguments to restrict_chat_member method 2017-06-30 20:16:51 +03:00
25a37db2bb Bot API v3.1 2017-06-30 19:47:09 +03:00
3e04df7080 Update README.md 2017-06-28 18:01:07 +08:00
6af3067a12 Add proxy to readme. 2017-06-28 17:44:07 +08:00
32c2178b29 Merge pull request #362 from BoberMod/patch-1
Using some content types in one function
2017-06-26 08:28:28 +08:00
6786f87d66 Using some content types in one function 2017-06-23 17:01:05 +03:00
ebdd7d107e Merge pull request #361 from ihoru/master
json.dumps(allowed_updates) before sending request
2017-06-22 14:55:35 +08:00
3713b093b6 json.dumps(allowed_updates) before sending request 2017-06-22 10:35:13 +07:00
242456d92b Update util.py 2017-06-20 15:45:18 +03:00
328cabead6 Update util.py 2017-06-20 15:45:01 +03:00
e834903bc2 Merge pull request #357 from gabolaev/fixDownloadingExample
Added file opening mode
2017-06-16 10:39:39 +08:00
556a04ca8b Added file opening mode 2017-06-16 02:57:12 +03:00
4b165ba3f1 Merge pull request #305 from MonsterDeveloper/patch-2
Added option to disable CherryPy logging
2017-06-02 16:13:56 +08:00
4e1d5b83b6 Merge pull request #349 from MasterGroosha/patch-2
Fixed wrong method call
2017-06-02 16:13:18 +08:00
cb4521f497 Fixed wrong method call
Should be called `apihelper.answer_shipping_query` instead of `apihelper.answer_shippingQuery`
2017-06-02 11:07:35 +03:00
52e50f1286 Merge pull request #347 from denkorzh/patch-1
Update README.md
2017-06-01 17:23:08 +08:00
3f626d37ba Update README.md
Fixed hyperlink formatting in the subtitle
2017-06-01 10:44:46 +03:00
d6aaf0716a Update version.
Change log:
- Fix #314
2017-05-30 17:19:03 +08:00
777a3afaaa Fix #314 2017-05-30 17:18:03 +08:00
0b1ae6ad8b Update version. 2017-05-30 17:18:03 +08:00
7aca24a18b Merge pull request #346 from Kylmakalle/master
Added payments example
2017-05-26 11:05:40 +08:00
754ca77394 Add payments bot example 2017-05-25 21:00:48 +03:00
5ffd9c5755 Merge remote-tracking branch 'refs/remotes/eternnoir/master' 2017-05-25 20:46:10 +03:00
639218b3bf New fields gif_duration in InlineQueryResultGif and mpeg4_duration in
InlineQueryResultMpeg4Gif.
2017-05-25 13:27:13 +08:00
b2449e64c2 Add pay in inline keyboard btn, 2017-05-25 11:48:16 +08:00
708635e420 Fix handler. 2017-05-25 11:45:44 +08:00
84b1aca939 Fix method name. 2017-05-25 11:23:37 +08:00
9025be0ef2 Add handlers. 2017-05-25 11:22:40 +08:00
a8e60b28e0 Fix requirement params. 2017-05-25 11:14:08 +08:00
cf287af549 Add payment method. PEP8. Refactor. 2017-05-25 10:56:58 +08:00
2d10793686 Merge pull request #343 from Kylmakalle/feature-BotAPIV3
Payments methods
2017-05-24 14:31:11 +08:00
3a10c90799 Payments methods 2017-05-24 01:23:52 +03:00
f8fed5c942 Merge remote-tracking branch 'refs/remotes/eternnoir/feature-BotAPIV3' into feature-BotAPIV3 2017-05-23 23:37:33 +03:00
12791e1366 Add payments type to update and message. 2017-05-21 21:52:56 +08:00
5ed333492b All payment type done. 2017-05-21 21:45:12 +08:00
9134e8dd1a Add send video note test case. 2017-05-21 19:58:00 +08:00
43a30e7777 Merge pull request #338 from Kylmakalle/feature-BotAPIV3
Video Note support.
2017-05-21 19:47:30 +08:00
3f5596ddce new_chat_members content type and new send_action actions 2017-05-21 14:27:31 +03:00
443d81d4db FIX: Can't edit file bytes 2017-05-19 18:08:07 +03:00
6cda8d052c VideoNote support
Send and recieve round video messages.
Support for send_video_note metod and video_note content type.
2017-05-19 17:19:15 +03:00
5969a6644c Merge pull request #1 from eternnoir/master
Merging to master
2017-05-19 16:22:07 +03:00
791a183af5 Merge pull request #336 from i32ropie/master
Added language code for users
2017-05-19 10:04:30 +08:00
35214b1270 Added language code for users 2017-05-18 23:40:10 +02:00
50ea288c9e Merge pull request #333 from Kurbezz/master
Add methods to AsyncTeleBot
2017-05-18 21:52:18 +08:00
34047c0121 Add methods to AsyncTeleBot 2017-05-18 13:55:55 +04:00
1a70c2d613 Merge pull request #319 from Artom-Kozincev/master
Add more accurate control over threads count
2017-05-17 14:48:18 +08:00
6d18a2c22f Merge pull request #325 from Kylmakalle/master
Added option to delete messages.
2017-05-16 16:54:34 +08:00
89f515b120 deleteMessage returns Ok on success, not Message type 2017-05-12 01:13:40 +03:00
11f0733974 Merge pull request #326 from jiwidi/master
Update readme
2017-05-08 10:25:54 +08:00
b91eeb2752 Update readme 2017-05-07 18:27:04 +02:00
f7cfb98b60 Added option to delete messages.
Added option to delete messages.

Some bots do not support this method now, waiting for an official api
release.
2017-05-07 17:37:03 +03:00
8bf226e6bf Bump version. 2017-04-30 20:37:55 +08:00
450ef42a83 Fix typo. 2017-04-30 19:40:27 +08:00
4fc83a85ee Merge pull request #321 from bryant1410/master
Fix broken headings in Markdown files
2017-04-18 13:31:55 +08:00
8dca85b1f2 Fix broken Markdown headings 2017-04-18 01:38:53 -03:00
fc65b30e3a Update README.md 2017-04-15 23:27:07 +08:00
e138d2e1ef Add more accurate control over threads count 2017-04-06 22:12:17 +03:00
d29c816b79 Merge pull request #318 from ihoru/master
RecursionError fix during sending files
2017-04-05 14:13:22 +08:00
f220a68c00 Merge pull request #312 from MonsterDeveloper/patch-3
Added webhook example with Tornado
2017-04-05 14:12:45 +08:00
94d723cf7b Merge pull request #317 from MonsterDeveloper/patch-4
Added IGNORECASE flag to message_handler
2017-04-05 14:12:07 +08:00
662c69e09c RecursionError fix during sending files 2017-04-02 14:56:53 +07:00
43f026dc64 Added IGNORECASE flag to message_handler
Added re.IGNORECASE flag to message_handler, so it matches without chars case.
2017-03-28 16:24:28 +03:00
2c631b2973 Added webhook example with Tornado 2017-03-23 15:34:33 +03:00
401a848927 Added option to disable CherryPy logging 2017-03-07 21:43:14 +03:00
7f31f8dde8 Merge pull request #294 from bace1996/patch-1
Fixed README.MD
2017-03-05 20:18:07 +08:00
19b8b4d2bf Fix readme image url link 2017-03-05 20:17:46 +08:00
6515c7c494 Update version. 2017-03-04 21:30:35 +08:00
76a48ffe82 Bug fix for edited_channel_post_handler. 2017-03-04 21:30:07 +08:00
f8f0e0c343 Update Bots using this API list 2017-03-03 11:00:03 +08:00
8129b95118 Fixed README.MD
Fixed a problem that could not jump to "Using web hooks" correctly
2017-02-15 21:31:52 +08:00
2b7e9a6180 Merge pull request #293 from MonsterDeveloper/patch-1
Fixed typo: from plan to plain
2017-02-10 15:33:03 +08:00
a84c0b984b Fixed typo: from plan to plain
Line 184: from `return message.document.mime_type == 'text/plan'` to `return message.document.mime_type == 'text/plain'`
2017-02-09 16:49:15 +03:00
a356c9a325 Merge pull request #283 from roboxv/master
Extend examples with aiohttp
2017-02-02 10:45:49 +08:00
4c4e8deaee Merge pull request #284 from Kuznitsin/master
Non-ASCII chars for filename.
2017-02-02 10:45:19 +08:00
f7fc538bd8 Non-ASCII chars for filename. Telegram doesn't accept rfc2231 styled filename. Using utf-8 directly. 2017-01-30 17:40:18 +03:00
6c770d81f9 Extend examples with aiohttp 2017-01-30 01:54:49 +06:00
d6af33fef7 Merge pull request #277 from i32ropie/master
Updated from ReplyKeyboardHide() methode to ReplyKeyboardRemove()
2017-01-23 11:21:10 +08:00
b6fee07089 Updated from ReplyKeyboardHide() methode to ReplyKeyboardRemove() 2017-01-20 10:55:34 +01:00
a5d6b541a5 Update README.md 2017-01-15 00:57:05 +08:00
ecad88ad00 Merge pull request #275 from mefuckin/patch-1
Fix error in webhook flask example
2017-01-05 11:02:10 +08:00
be87e4b2b9 Fix error in webhook flask example 2017-01-04 21:50:09 +03:00
1215eee167 Merge pull request #272 from mymedia2/persistent-connection
Use session to ensure persistent connection to api.telegram.org
2016-12-20 00:57:22 +08:00
9fe8565d53 Use session to ensure persistent connection to api.telegram.org 2016-12-17 09:03:00 +03:00
1058822f85 Merge pull request #266 from Yolley/patch-1
Added isinstance for bytes to function 'add' in ReplyKeyboardMarkup
2016-12-13 10:02:58 +08:00
57a57c8aca Merge pull request #268 from MasterGroosha/patch-1
Added max_connections and allowed updates to WebhookInfo
2016-12-13 09:45:55 +08:00
12e7879325 Added max_connections and allowed updates to WebhookInfo 2016-12-12 19:29:57 +03:00
d14bd9a36b Add isinstance for bytes to function 'add' in ReplyKeyboardMarkup
All explanation is here https://github.com/eternnoir/pyTelegramBotAPI/issues/265
2016-12-06 17:12:28 +03:00
c168feea32 Version update:
Change log:
- Telegram bot api 20161121 new feature.
- Telegram bot api 20161204 new feature.
2016-12-06 12:09:28 +08:00
a06551daaf Add delete webhook. 2016-12-06 11:52:16 +08:00
eadff07f79 Add allowed_updates to get_updates. 2016-12-06 11:44:30 +08:00
b5e27d0fea Add max_connections and allowed_updates to set_webhook. 2016-12-06 11:42:15 +08:00
509fae6792 Bug fix. 2016-12-03 15:17:06 +08:00
b0bc49c803 Update readme. 2016-12-03 13:56:22 +08:00
e555da86dd Add cache_time to answerCallbackQuery 2016-12-03 13:38:30 +08:00
9a5e8302be Add force params in setGameScore method. 2016-12-03 13:31:55 +08:00
30ed6e37d3 Add channel_post, edited_channel_post support. 2016-12-03 13:28:22 +08:00
27a79c4be5 Merge pull request #254 from Kondra007/patch-2
Bot API November updates
2016-11-25 08:27:15 +08:00
c99bb16619 Updated set_game_score
• New field `force`
• Changed `edit_message` to `disable_edit_message`
2016-11-21 09:28:32 +03:00
856af72599 Added cache_time to answer_callback_query 2016-11-21 09:19:59 +03:00
8c8be81bb9 Added optional forward_from_message_id
And changed `forward_date` to optional (as it should be)
2016-11-21 09:10:51 +03:00
b2cd3c9716 Added channel_post and edited_channel_post to Update object 2016-11-21 09:06:36 +03:00
1c9a9b9622 hide_keyboard -> remove_keyboard 2016-11-21 08:57:38 +03:00
f413ccf3fb Merge pull request #257 from rmed/wat-bridge
Added wat-bridge to the list of bots
2016-11-21 10:37:01 +08:00
9aaa00c8fd Added wat-bridge to the list of bots 2016-11-20 19:04:21 +00:00
11c2505d50 Update readme. 2016-11-18 19:37:29 +08:00
91076d0b59 Add dailypepebot to list. 2016-11-18 19:37:00 +08:00
1691e84d01 ReplyKeyboardHide -> ReplyKeyboardRemove
Since Telegram changed object name in API docs: https://core.telegram.org/bots/api#replykeyboardremove
2016-11-16 14:18:39 +03:00
903de2a72c Merge pull request #252 from DmytryiStriletskyi/striletskyi
Update README.md
2016-11-11 15:03:15 +08:00
9ddc529b28 Update README.md 2016-11-09 20:24:27 +02:00
d9ca776e2c Update README.md 2016-11-09 20:03:28 +02:00
2c497edca6 Update README.md 2016-11-03 16:43:46 +08:00
bf6634bc36 Version update.
Chnage log:
- Fix InlineQueryResultGame's reply_makrup bug.
- Remove type param from InlineQueryResultGame contractor.
2016-11-01 01:23:51 +08:00
2455d7013c Merge branch 'bug-fixInlineQueryResultGame' 2016-11-01 01:23:21 +08:00
7a6bb4dcc8 Remove type in InlineQueryResultGame. 2016-11-01 01:14:28 +08:00
e342b9fa6b Fix InlineQueryResultGame replymarkup do not to_dic. 2016-11-01 01:10:06 +08:00
2e8151cb7d Version update. 2016-10-31 00:35:07 +08:00
2af9209005 Fixed KeyError when data field is None in CallbackQuery
obj['data'] raises KeyError when `data` is None, while obj.get('data') returns None
2016-10-30 18:23:57 +08:00
34b0a2404e Version change.
Change log:
- bug fix.
2016-10-30 07:05:15 +08:00
f6d5358d1a Merge pull request #245 from Kondra007/patch-11
Fixed API object type mismatch
2016-10-30 07:03:53 +08:00
d2e1acde6a Fixed API object type mismatch 2016-10-29 23:23:39 +03:00
aad9251d48 Version update.
Change log:
* Gaming platform new methods.
* Other change in October 3, 2016 update.
(https://core.telegram.org/bots/api/#recent-changes)
2016-10-29 21:44:02 +08:00
54ed2038aa New methods setGameScore and getGameHighScores. 2016-10-29 21:22:46 +08:00
1b767215b5 Merge pull request #243 from Kondra007/patch-10
Added setGameScore and getGameHighScores
2016-10-27 10:41:47 +08:00
6f8ebbae89 Added setGameScore and getGameHighScores
1. https://core.telegram.org/bots/api#setgamescore
2. https://core.telegram.org/bots/api#getgamehighscores
2016-10-26 16:19:04 +03:00
d1498979d4 Merge branch 'JrooTJunior-master' into feature-20161003update 2016-10-20 20:09:07 +08:00
702763edd6 Get webhook info
https://core.telegram.org/bots/api#getwebhookinfo
2016-10-20 10:52:38 +03:00
ffa0ea449b Fix test case. 2016-10-12 15:52:34 +08:00
d53a881ac4 Merge pull request #238 from Kondra007/patch-6
Added "all_members_are_administrators" field to Chat object
2016-10-12 12:01:46 +08:00
67583d3639 Merge pull request #240 from Kondra007/patch-9
Added caption field to several objects
2016-10-12 12:00:32 +08:00
0f3398ed2f Merge pull request #239 from Kondra007/patch-7
Added Caption field to sendAudio & sendVoice
2016-10-12 11:59:15 +08:00
08dd7d1593 Added caption field to several objects
InlineQueryResultAudio, InlineQueryResultVoice, InlineQueryResultCachedAudio, InlineQueryResultCachedVoice
2016-10-11 22:57:16 +03:00
7e94810ece Added Caption field to sendAudio & sendVoice 2016-10-11 22:51:20 +03:00
11aa5fcb85 Added "all_members_are_administrators" field to Chat object 2016-10-11 22:43:44 +03:00
8d65856dec New field callback_game in InlineKeyboardButton, new fields
game_short_name and chat_instance in CallbackQuery.
2016-10-08 22:04:44 +08:00
740d7f44cf Add url param in answer inline query. 2016-10-08 21:55:28 +08:00
b8e5c43598 Add send game method. 2016-10-08 20:36:48 +08:00
795a00f92c Add game in Message. InlineQueryResultGame 2016-10-08 20:06:08 +08:00
de740be506 Add class Game,Animation,GameHighScore. For Game feature. 2016-10-08 19:50:29 +08:00
cd89de5a9a Update README.md 2016-09-29 13:35:42 +08:00
4dc2d5f1db Update README.md 2016-09-29 13:25:01 +08:00
1b0a872619 return statement added to callback_query_handler in decorator 2016-09-28 20:07:15 +08:00
82cf5535dd Merge pull request #230 from Kondra007/patch-6
Update Readme.md
2016-09-19 10:59:01 +08:00
48002f280b Update Readme.md
Added new content_types names in documentation.
2016-09-18 20:36:40 +03:00
057d130baa Update README.md 2016-09-17 20:32:54 +08:00
88e49bdaef Update test case. 2016-09-17 07:55:25 +08:00
acdc2058c5 Version change.
Change log:
- Fix venue's location not dejson to Location object.
2016-09-17 07:49:05 +08:00
a5ed76018d Fix venue Loacation dejson. 2016-09-17 07:38:18 +08:00
bac269d48a Update pytest. 2016-09-12 17:13:48 +08:00
e69790a8fc CI support py3.5. 2016-09-12 16:53:48 +08:00
590b27ca8a Add ujson support. 2016-09-12 16:38:54 +08:00
404f81fd43 Version update.
Change log:
- bugs fix.
2016-08-29 21:50:26 +08:00
89cf2658ae Fix edit reply markup return bool. 2016-08-29 20:50:27 +08:00
ea92e8696e Fix test case. 2016-08-29 20:48:09 +08:00
6da88c9751 FIx #225 2016-08-29 20:21:56 +08:00
ff5f6f727a Fix document #220 2016-08-11 22:46:40 +08:00
315400de47 Merge pull request #219 from olshevskiy87/t1
fix relative link for "callback query handlers" in readme
2016-08-10 10:37:36 +08:00
ca33801565 fix relative link for "callback query handlers" in readme 2016-08-09 16:17:45 +03:00
c61b82ace6 Update create_threads to threads. #198 2016-07-17 23:38:37 +08:00
8a4d2000d2 Update message's content_type doc. #199 2016-07-17 23:36:43 +08:00
f9d7f6905b Merge pull request #209 from QtRoS/master
Example of inline bot fixed
2016-07-17 23:15:34 +08:00
124b550de5 Merge pull request #1 from QtRoS/QtRoS-inline-bot-fix
Example of inline bot fixed
2016-07-17 15:55:11 +03:00
653c892b33 Example of inline bot fixed 2016-07-17 15:54:26 +03:00
b79c3165a1 Add issue templaate. 2016-07-11 21:45:52 +08:00
303406020b Update version. 2016-07-11 21:45:52 +08:00
3dcd59c22e Fix example 2016-07-11 21:29:25 +08:00
d847cfb9fa Merge branch 'bug-fix#202' 2016-07-06 10:22:55 +08:00
4205e46608 Fix missing location object in InlineQuery. 2016-07-06 10:13:42 +08:00
2044fba29a Update version. 2016-06-17 17:55:53 +08:00
29ef0e74af Fix typo. 2016-06-17 17:50:06 +08:00
46fc8da79e Merge pull request #197 from aivel/master
+ More flexibility for different handlers(callback_query_handler and etc.)
2016-06-17 01:22:07 +08:00
Max
b9a0c3e511 + More flexibility for different handlers(callback_query_handler and
etc.): now they are not limited in input arguments so can be easily
extended by subclassing

arguments
2016-06-16 11:49:51 +03:00
a4ac83aec2 Merge pull request #196 from auveele/patch-1
Update README.md
2016-06-15 20:03:22 +08:00
70fa5b405a Update README.md 2016-06-15 13:30:57 +02:00
c7d2731559 Merge pull request #195 from aivel/master
Some changes to make the library more flexible in terms of extensibility
2016-06-13 22:33:42 +08:00
Max
527351385b + Don't check filters against NoneType values;
+ More flexibility for subclassing:
	- __exec_task is protected now(was private)
	- _test_message_handler and _test_filter are class members
	  now(used to be static methods)
+ More flexibility on extention of message_handler(**kwargs for
additional parameters)
2016-06-13 16:47:15 +03:00
Max
1b47e5cc62 code duplication lessened 2016-06-13 14:24:27 +03:00
Max
eb4d58bec1 little optimization on handler dictionary building: code duplication lessened 2016-06-13 14:15:15 +03:00
57486b18cd Remove download count from readme. 2016-06-07 20:04:19 +08:00
25ad3f055f Update version.
Change log:
- Added new methods: getChat, leaveChat, getChatAdministrators,
  getChatMember, getChatMembersCount.
- New fields: edited_message in Update, edit_date in Message, user in
  MessageEntity. New value text_mention for the type field in
MessageEntity.
2016-06-07 19:57:40 +08:00
cdb6d6760d Add some comment. 2016-06-07 19:44:30 +08:00
5bd8e9d3f5 Update readme. 2016-06-07 19:40:35 +08:00
fab2f324d0 Fix test case. 2016-06-07 19:34:46 +08:00
9bf4be2caf fix test case. 2016-06-07 19:32:12 +08:00
d701fd6e1d Merge remote-tracking branch 'origin/feature-changes20160522' into api2.1 2016-06-07 19:30:01 +08:00
8e3c9d8d24 Add edited message handler. 2016-06-07 19:29:12 +08:00
0b9f91c6fb Add new method test case. 2016-06-07 19:16:17 +08:00
468a535257 Fix de_json. 2016-06-07 19:08:52 +08:00
d2e7f4d8f2 Add 2.1 new method. 2016-06-07 19:00:44 +08:00
ddd3664329 Merge pull request #192 from alejandrocq/comedoresugrbot
Add ComedoresUGRbot to bots list.
2016-06-06 01:32:45 +08:00
9e397c41cf ComedoresUGRbot added to bots list. 2016-06-05 19:20:17 +02:00
b528b0bcf0 Merge pull request #191 from Ledokol/uni-json
unicode strings for check_json
2016-06-05 18:36:36 +08:00
2f20d70e89 unicode strings for check_json 2016-06-04 21:18:09 +05:00
ac740e4755 Change public link to invite link. 2016-06-03 17:21:33 +08:00
2cf8ffcbc0 Update group link. 2016-06-03 14:45:25 +08:00
87ad4a62ff Merge pull request #187 from GabrielRF/master
Added Send2KindleBot
2016-06-03 00:06:10 +08:00
6b255deed7 Added Send2KindleBot
Also added description of urlprobot and lmgtfy_bot
2016-06-02 12:04:04 -03:00
ce24aa25f2 Fix #179. 2016-06-02 13:25:50 +08:00
a0f25089e0 Merge pull request #177 from qwidim/master
heroku webhook example
2016-06-02 13:17:12 +08:00
1bfdf7cf35 Merge pull request #173 from dmcelectrico/master
Added optional connection (aka sending) timeouts to methods that may …
2016-05-31 02:11:31 +08:00
5b1de9f339 Merge pull request #181 from PowerInside/patch-1
Fix inline demo code in readme.md
2016-05-29 22:29:21 +08:00
e956800e34 Fix inline demo code in readme.md 2016-05-29 19:25:36 +05:30
b9a57f630a Merge pull request #178 from Kondra007/patch-5
Update Readme.md
2016-05-26 11:02:30 +08:00
851d76888b Update Readme.md
Added `user` to attributes list
2016-05-26 00:44:39 +03:00
05f1c87c7d Update webhook_flask_heroku_echo.py 2016-05-25 19:25:46 +06:00
59b19fbbc1 Update webhook_flask_heroku_echo.py 2016-05-25 19:15:13 +06:00
e87907f0b8 Update webhook_flask_heroku_echo.py 2016-05-25 01:44:09 +06:00
d84aa796c0 Add files via upload 2016-05-25 01:42:25 +06:00
8c20f63022 Add user to MessageEntity. 2016-05-23 11:12:20 +08:00
f9c7497c5c Merge branch 'Kondra007-patch-3' into feature-changes20160522 2016-05-23 11:05:14 +08:00
3413669a23 Added optional connection (aka sending) timeouts to methods that may upload big chunks of data: send_audio, send_voice, send_document, send_sticker and send_video. 2016-05-22 18:35:20 +02:00
1a45b4844a Fixed Travis build (again)
Yeah, I'm really sorry for all this errors, maybe tired a little bit.
2016-05-22 15:47:44 +03:00
8a9d89591b Fixed Travis build errors 2016-05-22 15:44:04 +03:00
234dd8cf9f Edited edit_date field
It's integer, not `Message`
2016-05-22 13:55:54 +03:00
6a98d27f1a Added edited_message to Update object
As of Bot API update 2.1, Update object now has optional edited_message field.
2016-05-22 13:35:21 +03:00
04df139efb Added edit_date to Message object
As of Bot API update 2.1, `Message` object now has optional `edit_date` field.
2016-05-22 13:32:53 +03:00
747f14216b Merge pull request #166 from Kondra007/patch-1
Changed "Process_new_message" to "Process_new_update"
2016-05-20 23:23:10 +08:00
aee9255568 Changed "Process_new_message" to "Process_new_update"
This way all types of queries (Message, Inline query, Callback query) are supported.
2016-05-20 17:40:22 +03:00
fbaf88c237 Update version. 2016-05-20 14:41:00 +08:00
3ebc47de8b Add missing title in InlineQueryResultVenue. #165 2016-05-20 14:39:34 +08:00
8017c8d919 Fix failing build for python 3.3, 3.4 and pypy3 2016-05-19 10:18:00 +02:00
2545724a6f Fix #164 2016-05-19 10:02:59 +02:00
b8770e2c04 Merge pull request #163 from agentik-007/patch-1
Update webhook_flask_echo_bot.py
2016-05-17 08:41:34 +08:00
1da5d1e0e2 Update webhook_flask_echo_bot.py 2016-05-16 14:31:36 +03:00
bc73f345b2 Update README.md 2016-05-15 09:40:56 +08:00
a824ff967b Version update. 2016-05-12 11:39:50 +08:00
0c420ee5e4 Add missing title to InlineQueryResultLocation to_json.
Fix #160
2016-05-12 11:09:21 +08:00
16838c30b6 Update version.
Change log:
- Added the field emoji to the Sticker.
- Added the field forward_from_chat to the Message object for messages
  forwarded from channels.
2016-05-08 18:45:21 +08:00
022cdada49 Merge pull request #157 from Kondra007/patch-6
Added 06.05.16 updates
2016-05-08 10:45:28 +08:00
fb1052824c Added 06.05.16 updates
* Added the field emoji to the Sticker object. Your bot can now know the emoji a sticker corresponds to.
* Added the field forwarded_from_chat to the Message object for messages forwarded from channels.
2016-05-07 20:24:16 +03:00
769bb55bbe Update test. 2016-05-03 21:05:11 +08:00
655940dcf8 Update version. 2016-05-03 21:02:46 +08:00
3b52e5c49b ReplyKeyboardMarkup support string. 2016-05-03 21:02:46 +08:00
700b869555 Merge pull request #154 from tp6vup54/master
Fix the bug that the return of request.get_data() is not string.
2016-05-02 21:12:29 +08:00
5906d632d6 Fix the bug that the return of request.get_data() is not string. 2016-05-02 11:07:23 +00:00
bd513cd343 Merge branch 'master' of github.com:eternnoir/pyTelegramBotAPI 2016-05-01 00:25:28 +08:00
0cb99b42e4 Update version. 2016-05-01 00:25:10 +08:00
dc1869167d Fix #153 2016-05-01 00:24:54 +08:00
ef22fafa7e Merge pull request #146 from rmed/fix-regexp
Added missing import for extract_arguments()
2016-04-26 23:14:38 +08:00
94d1b3f7a8 Added missing import for extract_arguments() 2016-04-26 11:16:49 +02:00
ef68bed01f Version update. 2016-04-25 23:55:03 +08:00
0eb21aa673 Fix #138. 2016-04-25 23:54:30 +08:00
e6105d851c Merge pull request #142 from Pitasi/master
Fixed new/left_chat_member content types
2016-04-25 23:32:44 +08:00
7ec33d43b3 Fixed supper for new/left_chat_member content types 2016-04-24 17:53:13 +02:00
0a856f4e83 Fix test case. 2016-04-23 09:29:48 +08:00
bbe53b5e17 Fix #136 and Update version. 2016-04-23 01:24:50 +08:00
84257b6ba9 Fix typo. 2016-04-23 01:21:45 +08:00
5b234920c7 Version Update.
Change log:
- duplicated code remove.
2016-04-19 08:19:20 +08:00
16d4c64b00 Remove duplicated method. 2016-04-19 08:13:37 +08:00
4fb85e25f6 Update rst readme. 2016-04-18 13:39:00 +08:00
0ae20e1a49 Update version. 2016-04-18 13:37:24 +08:00
e913635755 fix next_offset is empty will not set bug. 2016-04-17 23:28:47 +08:00
225cbf2c61 Update switch_inline_query is empty not set bug. 2016-04-17 23:21:11 +08:00
ae63b8029f Merge pull request #134 from Kondra007/patch-5
Fixed typo in types.py
2016-04-17 22:58:37 +08:00
e47790ded8 Fixed typo in types.py
"switch_inline_quer" -> "switch_inline_query"
2016-04-17 17:54:01 +03:00
d0666071d8 Fix edit inlinemessage will return bool not Message object. 2016-04-17 10:24:37 +08:00
eb8e87fdec Merge pull request #133 from Kondra007/patch-4
Fix Readme.md
2016-04-17 10:24:15 +08:00
1c98e1108c Fix Readme.md
Fixed Readme so "Bot 2.0" link leads to proper paragraph
2016-04-16 22:24:48 +03:00
8a0bf8ca7e Update readme. 2016-04-16 15:08:01 +08:00
7490f63f25 Add send_contact 2016-04-16 15:07:52 +08:00
22ab50989e Add answer_callback_query. 2016-04-16 14:53:41 +08:00
1e320a5b0d Add callback query handler. 2016-04-16 14:18:19 +08:00
96e06c248b Merge pull request #131 from Kondra007/patch-4
Fixed typo in InlineQueryResultAudio
2016-04-16 11:22:33 +08:00
ae92d1998e Fixed typo in InlineQueryResultArticle 2016-04-15 21:04:08 +03:00
d87e0821c9 Fix type test. 2016-04-14 17:45:57 +08:00
ee52241cc2 Update inline example. 2016-04-14 17:43:45 +08:00
a6d35fd1de Add all inquery types. 2016-04-14 17:09:12 +08:00
016819cd44 Add inline query classes. 2016-04-14 16:57:23 +08:00
036441b8f6 Add new inline type. 2016-04-14 15:50:55 +08:00
228683aeda Add new param for anser inline query. 2016-04-14 15:32:08 +08:00
4fe4061a0f All Updating messages methods done. 2016-04-14 15:17:53 +08:00
f873658aac Fix edit message error. 2016-04-14 15:06:46 +08:00
13327c371a Add editMessageText. 2016-04-14 15:03:07 +08:00
4dc7af71a0 Add bot2.0 new methods. 2016-04-14 14:48:26 +08:00
209764a5d7 Add connect timeout. Fix #108 2016-04-14 14:34:37 +08:00
c1247249c7 Add send venu method. 2016-04-14 13:55:28 +08:00
a6b0e9598c Add inline keyboard test. 2016-04-14 13:35:18 +08:00
7958264d64 Add bot 2.0 markup. 2016-04-14 12:01:17 +08:00
74c3a3545d Update type message to bot2.0 define. 2016-04-14 11:15:58 +08:00
7b007dab99 Add venue to message type. 2016-04-14 11:02:19 +08:00
8316a57845 Add type Venue. 2016-04-14 11:00:33 +08:00
2eb914d329 Add message entity to message. 2016-04-14 10:57:18 +08:00
2449a3ea64 Add MessageEntity. 2016-04-14 10:51:05 +08:00
a2d91808ef Remove pytest. 2016-04-09 10:37:34 +08:00
23dd31752b Update README.md 2016-04-04 10:51:27 +08:00
7770fcbb33 Update README.md 2016-03-29 11:34:37 +08:00
c64fdf149e Merge pull request #121 from DrBomb/patch-1
extract_argument
2016-03-18 15:09:21 +08:00
17184697ea Update util.py
Another typo
2016-03-17 22:17:06 -04:30
78d86752fb Update util.py
Typo
2016-03-17 00:51:02 -04:30
7669781737 Update util.py
Added a regexp method that returns all the text after the command.
2016-03-17 00:48:08 -04:30
ddc1a4d66f Version Update.
Change log:
- Add disable_notification parameter.
- Added setters for message/inline/chosen-inline handlers.
2016-02-27 11:47:01 +08:00
3d9e012c40 Merge pull request #120 from eternnoir/feature-disable_notification
Feature disable notification
2016-02-27 11:45:23 +08:00
9b9c0287ec Add test case. 2016-02-27 11:36:53 +08:00
292191038f Add disable_notification 2016-02-27 11:17:35 +08:00
f0e157213c Merge pull request #119 from Kondra007/patch-4
Update README.md
2016-02-26 20:45:54 +08:00
18330275bd Corrected author of Proxy Bot 2016-02-26 15:34:14 +03:00
d173681a7c Update README.md 2016-02-25 20:49:45 +08:00
0830f2a0f9 Update README.md 2016-02-23 21:16:35 +08:00
45d6f8980c Merge pull request #117 from Dejust/add-handler-setters
Added setters for message/inline/chosen-inline handlers.
2016-02-21 10:56:22 +08:00
28417d18af Added ability to set message handler, inline handler, chosen inline handler with method calling 2016-02-20 17:51:14 +05:00
e0ae119512 Merge pull request #116 from idlesign/patch-1
answer_inline_query() made POST
2016-02-15 16:19:55 +08:00
e851f37712 answer_inline_query made POST
The default GET produces `414 Request-URI Too Large` response.
2016-02-14 00:08:37 +05:00
40cf8d6903 Update README.md 2016-02-14 02:00:00 +08:00
e507463741 Update README.md 2016-02-14 01:59:31 +08:00
3a055734f9 Update README.md 2016-02-14 01:52:46 +08:00
16ec573c9e Add more example. 2016-02-11 21:42:07 +08:00
2cd19a1a39 Merge pull request #113 from ratijas/master
__retrieve_updates split into process_new_updates
2016-02-08 23:09:15 +08:00
5f9cf881e6 __retrieve_updates split into process_new_updates 2016-02-07 23:45:54 +08:00
baacafe3c0 Update examples. 2016-02-01 22:50:47 +08:00
734767177d Merge pull request #110 from Kondra007/patch-4
Updated README
2016-01-25 09:50:18 +08:00
1e7f71029c Updated README
Added "supergroup" to message.chat examples.  
via https://core.telegram.org/bots/api-changelog#november-2015
2016-01-24 20:51:52 +03:00
02c22c990b Add chosen_inline_handler doc. 2016-01-19 13:56:44 +08:00
00d6481818 Version Update.
Change log:
- All Message's attributes default to None. Don't need hasattr to check
  attribute.
- Inline mode support.
- Add InlineQueryResultArticle InlineQueryResultPhoto
  InlineQueryResultGif InlineQueryResultMpeg4Gif InlineQueryResultVideo
- Add new method answer_inline_query
- Add new inline_handler
2016-01-06 21:26:28 +08:00
a74ed6e3ab Update some comment. 2016-01-06 16:59:42 +08:00
38eb2ba833 Add comment. 2016-01-06 15:53:35 +08:00
93dc1cd92e Add comment. 2016-01-06 14:31:21 +08:00
a7469e6b14 Merge branch 'master' of github.com:eternnoir/pyTelegramBotAPI 2016-01-05 22:25:02 +08:00
b8f251140d Fix thumb_url must have value. 2016-01-05 22:23:00 +08:00
e2e6b07fdb Update README.md 2016-01-05 22:00:34 +08:00
a2ceffecc8 Update README.md 2016-01-05 21:59:34 +08:00
805e3554de Update readme. 2016-01-05 21:54:47 +08:00
94d34747d1 Merge branch 'inline-mode' into develop 2016-01-05 15:35:45 +08:00
8278eef7f3 Add inline bot example. 2016-01-05 14:58:19 +08:00
94f1bbd402 Almost done. 2016-01-05 14:07:47 +08:00
c706a7aba3 Handler done. 2016-01-05 13:18:32 +08:00
c214f8000e Add InlineQueryResultVideo class. 2016-01-05 11:03:05 +08:00
81a201f19f Add InlineQueryResultMpeg4Gif class. 2016-01-05 10:51:33 +08:00
0f0d76ca82 Add InlineQueryResultGif class. 2016-01-05 10:41:32 +08:00
fa6f16ca5e Add InlineQueryResultPhoto class. 2016-01-05 10:24:21 +08:00
a1267a7670 Add InlineQueryResultArticle class. 2016-01-05 09:57:25 +08:00
79c46bccae inline_hanlder done. 2016-01-04 23:10:32 +08:00
e912546680 Add ChosenInlineResult class. 2016-01-04 22:53:08 +08:00
7eeda3bc4d Update update object. 2016-01-04 22:29:04 +08:00
b5680a1c1f Add InlineQuery class. 2016-01-04 22:24:18 +08:00
7514c617fc Merge branch 'master' into develop 2015-12-24 13:42:02 +08:00
32f3a64720 Update README.md 2015-12-24 11:25:19 +08:00
3a08111f10 Fix hasattr. 2015-12-22 14:26:08 +08:00
eeff4e7bf8 Let message all attribute default be None. #100 2015-12-22 14:18:23 +08:00
c37b3625aa Merge branch 'develop' of github.com:eternnoir/pyTelegramBotAPI into develop 2015-12-22 14:12:51 +08:00
a3519ff539 Merge pull request #97 from askainet/skip_pending_update
Get and discard all pending updates sent before first poll of the bot
2015-12-02 09:16:00 +08:00
43ad415320 Get and discard all pending updates sent before the first poll of the bot 2015-12-01 15:05:52 +01:00
fb7c79fdfb Merge pull request #95 from ratijas/master
style unification for method_url in apihelper.py.
2015-11-09 13:17:36 +08:00
413f081b19 style unification for method_url in apihelper.py. 2015-11-08 10:30:09 +08:00
cea0604ede Merge pull request #94 from Kondra007/patch-4
Added 'voice' to content_types + some small fixes
2015-11-06 22:01:36 +08:00
be639ef4dd Added 'voice' to content_types + some small fixes 2015-11-04 18:37:51 +03:00
528b23770f Update README.md 2015-10-26 22:36:32 +08:00
4e472dda48 Update README.md 2015-10-26 22:32:10 +08:00
17dec34923 Update README.md 2015-10-26 22:31:55 +08:00
a17b301f1c Jump to release version. 2015-10-26 22:26:04 +08:00
cf830a0fb4 Version update:
Change log:
- Code clean up
- Bugs fix
2015-10-26 22:15:03 +08:00
7e9f5b09cf Bug #92 fix. 2015-10-26 21:55:04 +08:00
969c5e76ef Fix bytes not string. 2015-10-18 22:03:29 +08:00
7346326bc3 Fix video's thumb type forgot de_json. 2015-10-17 02:30:22 +08:00
f355796b01 Merge pull request #88 from mabitte/develop
Little code cleanup
2015-10-17 02:08:34 +08:00
5175803d0b * dict.get(key) returns None if key is not in the dictionary
* used the class method's class reference to instantiate type classes
2015-10-15 16:53:59 +02:00
bf9939d40e Fix queue default value. #86 2015-10-13 13:05:38 +08:00
07960fe348 Update new type chat document. 2015-10-12 23:00:25 +08:00
f4be18e082 Update Version.
Change log:
- New type Chat support.
- Bugs fix.
2015-10-12 22:45:01 +08:00
8e9837a587 Merge branch 'develop' 2015-10-12 22:37:17 +08:00
361c043872 Fix test data error. 2015-10-12 11:02:10 +08:00
50432dbef1 Fix test data error. 2015-10-12 10:54:33 +08:00
37277d74cc Fix testing error. 2015-10-12 10:51:29 +08:00
9ee341f5e6 Add Chat test for telebot. 2015-10-12 10:46:20 +08:00
0bd284afc7 Format. 2015-10-12 10:37:41 +08:00
4ffdada427 Add Chat json test. 2015-10-12 10:37:25 +08:00
d8effd3f9f New type Chat supported. 2015-10-12 10:36:58 +08:00
303e15b88d Merge pull request #84 from AndydeCleyre/patch-1
Fix AttributeError on Python 3
2015-10-09 21:57:05 +08:00
3273aa9afa Merge pull request #85 from AndydeCleyre/patch-2
Fix NameError in Python 3
2015-10-09 12:21:23 +08:00
9e8b11051c Fix NameError in Python 3 2015-10-08 16:46:15 -04:00
b9d458e643 Fix AttributeError on Python 3 2015-10-08 16:39:22 -04:00
1e6361dd57 Fix #83
Added a `encode('utf8')` statement to support non-ASCII symbols in error log messages.
2015-10-06 22:36:57 +02:00
ca2019b8f1 Merge pull request #82 from skgsergio/webhook-examples
Add Webhook examples (CPython, Flask, CherryPy)
2015-10-06 13:17:10 +02:00
a230665424 Update README.rst 2015-10-06 12:19:20 +02:00
8eb6e034fe Update README with webhooks information. 2015-10-06 12:11:42 +02:00
d6552eb4c6 Add webhook examples 2015-10-06 12:06:23 +02:00
117c5a1141 Minor CPU optimization 2015-10-03 12:48:56 +02:00
3f335c37ce Update version.
Change log:
- Add webhook support.
- Better error handling.
- Add threaded parameter for telebot constructor. Allowing users to decide telebot to use thread for polling method.
2015-10-03 16:33:17 +08:00
e7e681928d Fix polling stuch problem. 2015-10-02 23:24:54 +08:00
855ff40070 Fix python3 raise exception error. 2015-10-02 17:08:05 +08:00
29a42a398b Restored the non-threaded variant 2015-10-02 00:00:54 +02:00
b801728924 Fix unnecessary raise 2015-10-01 22:43:18 +02:00
d14e9051d4 Better error handling.
Errors now are re-raised in the Thread polling() was called from.
If none_stop is *not* set, ApiExceptions will cause the calling Thread to halt.
2015-10-01 22:03:54 +02:00
60ca1751ca WorkerThreads now log ApiExceptions 2015-10-01 11:33:23 +02:00
941b8ac5d0 Added webhooks support with set_webhook and remove_webhook in the TeleBot class 2015-09-30 18:19:31 +02:00
7a08102fad Merge branch 'master' of https://github.com/eternnoir/pyTelegramBotAPI into develop 2015-09-30 17:51:45 +02:00
325061ee96 Added "Bots using this API" section to docs
Added Channel link to docs
2015-09-30 17:50:40 +02:00
8839f36706 Update version.
Change log:
- Bug fix : fix race-condition for register_for_reply.
- Add timeout parameter for polling method.
2015-09-30 23:34:37 +08:00
1c53955d5a Add timeout para for polling method. 2015-09-30 23:18:26 +08:00
9cd28b88be Merge pull request #79 from huiyiqun/master
fix race-condition for register_for_reply
2015-09-30 22:50:08 +08:00
2fb2cd6f20 fix race-condition for message_subscribers 2015-09-30 20:46:37 +08:00
036d000b95 Remove 3.2/3.5 2015-09-22 20:34:06 +08:00
11d4bb02a8 Add Test python version 2015-09-22 20:25:35 +08:00
f4b0b61b9d Update version.
Change log:
- Support File type.
- New method getFile supported.
2015-09-19 23:06:47 +08:00
4b8989f3d2 Merge pull request #74 from eternnoir/develop
Add getFile method and File type
2015-09-19 10:55:44 +08:00
19b4e35ee5 Attempt to fix failing test case 2015-09-18 21:11:56 +02:00
61b4ca8a37 Added download_file and created an example 2015-09-18 20:54:22 +02:00
1038d4fafa Added download_file 2015-09-18 20:53:10 +02:00
fd1f16598b Added File & getFile, including testing 2015-09-18 20:31:29 +02:00
07c28830db Update version.
Change log:
- Hotfix handler lambda bug.
2015-09-10 21:51:51 +08:00
a8fccdbeb3 Add test. 2015-09-10 21:44:14 +08:00
c213b7732b Add lambda text. 2015-09-10 21:38:09 +08:00
2ca5c0d6f3 Hotfix lambda bug. 2015-09-10 21:27:37 +08:00
2d0c54a7f2 Update version
Change log:
* send_message add parse_mode parameter support.
* Add get_updates method to telebot class.
* Remove time.sleep() from polling method. Use optional
* block parameter
2015-09-09 10:36:25 +08:00
bb0d028750 Add parse_mode markdown test. 2015-09-09 09:43:19 +08:00
e7b4e95fbc Merge remote-tracking branch 'origin/master' into develop 2015-09-09 09:34:13 +08:00
85ffe9936d Merge pull request #71 from eternnoir/implement-parse_mode
Implement parse_mode
2015-09-09 08:22:13 +08:00
99f6829ede Fix failing test case in Py2.6 because of using {} instead of {0..9} 2015-09-08 22:34:55 +02:00
55053fe413 Fixed failing test cases because of iteritems() 2015-09-08 22:31:02 +02:00
f2971c5d6c Merge branch 'redesign-message-handlers' into 'develop' 2015-09-08 22:22:01 +02:00
89288b166e Implement parse_mode 2015-09-08 21:51:45 +02:00
88bd6dcbb0 Updated Logging section in README 2015-09-08 19:56:05 +02:00
710fc273d6 Better log messages 2015-09-08 19:47:55 +02:00
9f04f0ece2 Fix "module has no attribute 'logger'" 2015-09-08 18:53:36 +02:00
cc7ab58ed8 Fixed some typos in the README
Fixed a bug where TeleBot would ignore KeyboardInterrupt events
2015-09-08 17:38:44 +02:00
edf1694606 Fix README message handler table 2015-09-08 11:29:35 +02:00
f9cbcf9b65 Redesigned message handlers 2015-09-08 10:44:31 +02:00
3a148c6e85 Refactor get_update method. 2015-09-05 21:54:54 +08:00
4522b37b9d Merge pull request #68 from eternnoir/refactor-Add-getUpdates-method
Refactor add get updates method
2015-09-05 18:25:53 +08:00
149c54cc31 Update readme.rst. 2015-09-05 18:13:47 +08:00
93aa37768a Add readme & pep8 2015-09-05 18:12:52 +08:00
da729069c2 Add get_updates method. 2015-09-05 18:10:11 +08:00
f7c4b14b77 Add types test. 2015-09-05 18:02:28 +08:00
2d5cb4fd75 Add Update class. 2015-09-05 17:58:53 +08:00
f2f556ed12 Merge pull request #67 from Kondra007/patch-1
Check if field is None
2015-09-03 17:40:34 +02:00
b1e659da28 Check if field is None
A slight change, still not very good though. Something like `{!s}{!s}{!s}.format(....)` seems a better aproach
2015-09-03 18:06:54 +03:00
4526c4f8a7 First TeleBot bot bug fix: wrong group chat id comparison (str and int) 2015-09-01 23:29:01 +02:00
efc98c084f Added TeleBot bot source 2015-09-01 23:20:24 +02:00
cf61577e3e Added a string representation (__str__) for JsonDeserializable 2015-09-01 21:55:02 +02:00
3c8faa155f Created util.py to clean up __init__.py and apihelper.py and updated README accordingly
Fixed failing send_document_by_id and send_photo_by_id
2015-08-31 11:49:03 +02:00
6f34a22c4b Added an incremental sleep when an error is encountered while polling 2015-08-31 02:14:14 +02:00
d118e9edcc Remove the deprecated time.sleep calls.
Reformatted detailed_example to follow Python naming conventions & PEP-8 conventions
2015-08-30 19:31:48 +02:00
c33c116488 Integrated blocking into polling + updated docs 2015-08-30 18:53:18 +02:00
e4bb2ff4f9 Merge branch 'develop' of github.com:eternnoir/pyTelegramBotAPI into develop 2015-08-24 10:43:01 +08:00
92fb982a57 Update travis ci script. 2015-08-24 10:42:32 +08:00
e734e0c974 Merge pull request #64 from pevdh/update-docs
Update docs
2015-08-24 10:39:14 +08:00
bf91d605ea Fix some more typos 2015-08-23 22:23:18 +02:00
e736c59896 Fix echo_bot example error 2015-08-23 22:06:11 +02:00
94844054e4 Added images 2015-08-23 21:56:42 +02:00
00f7c1ddc0 Fixed a typo 2015-08-23 20:07:53 +02:00
7f68bbbdb9 Copied to README.rst 2015-08-23 20:03:46 +02:00
2221b59b6f Updates after some reviews 2015-08-23 20:01:09 +02:00
3b61c7cd8a Update the documentation. 2015-08-23 19:32:23 +02:00
f2664d8232 Update version.
Change log:
- Add logging.basicConfig() to avoid handler not found.
2015-08-23 22:54:30 +08:00
4ed7be19ad Avoid no hnadler found. 2015-08-23 22:52:20 +08:00
93f1d9e6f8 Add readme.rst to repo. 2015-08-23 22:45:59 +08:00
2a103e5bbc Update version.
Change log:
- bug fix #61
- Better error description
2015-08-21 23:58:55 +08:00
645270861c Update readme. 2015-08-21 23:09:35 +08:00
ee4061561e Fix #61 2015-08-21 22:58:48 +08:00
b7a4d3f0b3 Merge pull request #60 from pevdh/better-error-description
Better error description
2015-08-20 15:07:17 +08:00
ee0ff8b1fb Fix test case 2015-08-19 22:15:40 +02:00
8412be1336 (Attempt to) fix failing Travis CI tests. 2015-08-19 22:13:27 +02:00
596df2ef2c Extended error descriptions
They should provide more information about the origin of the failure.
2015-08-19 21:30:44 +02:00
5c6de8aa04 Update version.
Change log:
- New type Voice
- Update audio
- sendAduio
- sendVoice
checkout: https://core.telegram.org/bots/api-changelog 20150815
2015-08-19 18:36:10 +08:00
7dc1c5095a Merge branch 'change20150815' into develop 2015-08-19 18:28:07 +08:00
b17831b726 Update Comment. 2015-08-19 18:27:35 +08:00
1517979bf2 Voice bug fix. 2015-08-19 18:25:08 +08:00
571a0fb320 Fix test case error. 2015-08-19 18:13:40 +08:00
c3300af656 New audio,voice supported. 2015-08-19 18:08:01 +08:00
cb4a58a1e8 Merge branch 'master' into develop 2015-08-14 15:42:30 +08:00
57ed31da71 Updare version.
Change log:
- fix mime_type syntax error.
2015-08-14 15:39:37 +08:00
fb3b63d441 Merge branch 'master' into develop 2015-08-10 09:05:57 +08:00
f06bec1a44 Merge pull request #57 from rjornetc/patch-1
Replaced mine_type by mime_type
2015-08-09 11:17:26 +08:00
b25435f29a Replaced mine_type by mime_type 2015-08-08 23:26:47 +02:00
a12ea63858 Update readme. 2015-08-01 21:03:40 +08:00
98f126d249 Update Version.
Change log:
- Some API method change.
- next_step_handler supported. #56
2015-08-01 10:20:41 +08:00
821a63e3a7 Support new sendVideo API method. 2015-08-01 10:12:15 +08:00
b745088a05 Let thumb option in Sticker. Api chamged. 2015-08-01 09:55:17 +08:00
8abd3fe140 Update text. 2015-07-30 11:40:54 +08:00
004f6917aa Fix test error. 2015-07-30 11:34:23 +08:00
d546a4f1e9 Add step handler example. 2015-07-30 11:30:16 +08:00
9f6a3bfb26 next_step_handler done. 2015-07-30 11:02:08 +08:00
a82fece950 Add method. 2015-07-30 09:23:15 +08:00
8f13b636ed Update version.
Change log:
- new method: register_for_reply
- Added a warning to send_message to not exceed 5000 characters per message.
2015-07-30 09:06:41 +08:00
740090640a PEP8 2015-07-30 09:03:08 +08:00
9219404a9a Merge branch 'sgomez-fix-video-type' into develop 2015-07-26 20:15:57 +08:00
d5c1601bf0 Merge branch 'master' into develop 2015-07-26 20:15:51 +08:00
83ab8a39c9 Fix video type class 2015-07-26 11:19:20 +02:00
3ffdd427dd Merge pull request #54 from pevdh/develop
Added split_string to apihelper.py
2015-07-26 11:25:36 +08:00
f41cc8134a Added split_string to apihelper.py
Added a warning to send_message to not exceed 5000 characters per message.
Changed send_message to use HTTP POST instead of GET, to stretch the maximum character limit a little more.
And added build status to README for fun.
2015-07-25 21:41:19 +02:00
20e3f731f7 Added split_string to apihelper.py
Added a warning to send_message to not exceed 5000 characters per message.
Changed send_message to use HTTP POST instead of GET, to stretch the maximum character limit a little more.
2015-07-25 21:31:58 +02:00
97f2c0c110 Merge pull request #52 from pevdh/develop
Implements #26
2015-07-24 21:24:10 +08:00
b484baea37 Fix doc error. 2015-07-24 13:56:47 +02:00
2647777b2b Implemented register_for_reply. Closes #26 2015-07-24 13:52:48 +02:00
b468e8c943 Moved extract_command and is_command to apihelper.py. 2015-07-24 13:09:27 +02:00
7b919852fa Update Readme. 2015-07-24 09:22:02 +08:00
60a7595b72 Update version.
Change log:
- Fix regexp handler bug.
- Fix python3 Exception message attribute not found.
2015-07-23 09:17:17 +08:00
893b414e33 Merge branch 'develop' 2015-07-23 09:16:44 +08:00
0932e603fb Fix python3 Exception message attribute not found. 2015-07-23 09:14:20 +08:00
2047b04a4c Update vsesion. Bug fix. 2015-07-22 14:49:52 +08:00
f513270971 PEP8. 2015-07-22 14:12:56 +08:00
53769f9e8c Merge branch 'fix_regexp_handler_fail' into develop
fix #48
2015-07-22 14:12:05 +08:00
ba1693dcf0 Bug fix. 2015-07-22 14:02:16 +08:00
f7168770ab Update Version.
Change log:
- Message type support forward_from forward_date reply_to_message
- Add logging.
2015-07-20 10:43:34 +08:00
43e1d26696 Update logger readme. 2015-07-20 10:38:33 +08:00
99b82b6219 Add logger. 2015-07-20 09:56:17 +08:00
968d30e246 Merge branch 'master' into develop 2015-07-18 17:35:46 +08:00
f183575d10 Merge pull request #41 from nasfarley88/master
Changed __stop_polling from bool to threading.Event().
2015-07-18 17:34:52 +08:00
edddab8956 Changed __stop_polling from bool to threading.Event(). 2015-07-18 10:27:16 +01:00
766b45e223 Update README.md 2015-07-17 21:40:33 +08:00
dd94b8624d Fix python3 test cases. 2015-07-17 14:50:56 +08:00
1350e19391 Add telebot tests. 2015-07-17 14:41:26 +08:00
6bdc313fa6 Message add forward_from forward_date reply_to_message support. 2015-07-17 14:40:49 +08:00
4870764b66 Add pypy to CI. 2015-07-17 13:56:34 +08:00
754d0ad558 Add python 3.4 to ci. 2015-07-17 11:31:00 +08:00
dbeec88ddf Update Version.
Change log:
- Bug fix. Python3 can not send file by string bug.
2015-07-17 09:38:28 +08:00
621b191e8d Fix python3 can not send file by string bug.
bug #40
2015-07-17 09:38:28 +08:00
634f88323c Add six package to requires. 2015-07-17 09:38:28 +08:00
55f6844d1f Add use file_id example 2015-07-15 13:14:46 +08:00
d5b7c2b49b Update README.md 2015-07-15 13:09:24 +08:00
1544efbbda Update version.
Change log:
- sendPhoto Document Audio ... file_id supported.
- Add process_new_message method for webhook.
- Fix thumb not in Document json
- Polling interval.
2015-07-15 11:28:21 +08:00
185b3e007e Polling interval support
issue #38
2015-07-15 11:19:29 +08:00
aeeb94d386 Fix api's document change. 2015-07-15 11:02:30 +08:00
56d1dfc045 Add some test. 2015-07-15 10:52:32 +08:00
6c8d30b063 Add process_new_message public method for webhook.
issue #36
2015-07-14 13:28:39 +08:00
c1bb900d91 send file, photo ...etc. by ID support. #35 2015-07-14 13:24:32 +08:00
0ee4fc8528 Updare version.
Change log:
- add none_stop flag to avoid polling stop.
2015-07-13 19:33:07 +08:00
bded9e021d Merge branch 'develop' of github.com:eternnoir/pyTelegramBotAPI into develop 2015-07-13 11:17:52 +08:00
913f01dfe8 Edit confused notice. 2015-07-13 09:07:07 +08:00
7144c79efe Add none_stop flag for polling method. 2015-07-13 09:07:07 +08:00
a9b51e039a Merge pull request #32 from LeoDJ/master
Updated detailed example to use message handlers
2015-07-12 22:49:37 +08:00
e5a17caa9f Updated detailed example to use message handlers
Now using message handlers instead of the listener for almost everything (except console output)
2015-07-12 15:50:50 +02:00
292bb307f0 Edit confused notice. 2015-07-12 19:03:41 +08:00
4a3e989391 Add none_stop flag for polling method. 2015-07-12 15:49:22 +08:00
09a39fcb89 Merge pull request #31 from LeoDJ/master
Created detailed example
2015-07-12 15:31:23 +08:00
efdf35796d Detailed example 2015-07-12 00:41:34 +02:00
bbf8b5d5f9 Added todo comment 2015-07-12 00:36:39 +02:00
30e3fbaa1a Created detailed example
Using almost every command, this API has to offer
2015-07-12 00:29:45 +02:00
8cf8661b7e Update README.md 2015-07-11 13:05:13 +08:00
2e1143e3d8 Update Version. 2015-07-09 10:39:08 +08:00
f6a0037f8d Fix thread pool high cpu usage. 2015-07-08 21:00:46 +08:00
3a574b4596 Update Version.
Change log:
- Thread pool support.
- Add create_thread flag.
2015-07-08 11:36:48 +08:00
45544d7b54 Update readme. 2015-07-07 11:51:11 +08:00
a82f4d780f Support python3 queue 2015-07-04 20:25:02 +08:00
814dbd2666 Remove python3.4 in ci 2015-07-04 20:13:56 +08:00
da176b770c Create ThreadPool when creat_thread flag is True. 2015-07-04 19:51:06 +08:00
b316e699e1 Fix failed testcase. 2015-07-04 17:27:53 +08:00
e095a2ffe9 Message handler support create_threads flag. 2015-07-04 17:20:29 +08:00
3d678707ac Add create_threads flag. 2015-07-04 17:00:42 +08:00
9b3f5f5ba0 Merge pool-impl branch 2015-07-04 02:42:41 +02:00
d71fdc633d Merge commit '0a2d139' into develop
Merge into develop
2015-07-04 02:34:05 +02:00
0a2d1394b2 Created a deep-linking example.
(Source: my answer at http://stackoverflow.com/questions/31042219/how-to-have-authentication-in-a-telegram-bot)
2015-07-04 02:32:43 +02:00
7dae316789 Merge pull request #24 from pevdh/master
Fix TeleBot#extract_command
2015-07-04 03:28:14 +08:00
bc181572d9 Merge commit '666ab76' into develop
Merge master.
2015-07-03 19:38:03 +02:00
e061aa051a Fixed API inconsistency (Message.fromUser -> Message.from_user) 2015-07-03 19:34:02 +02:00
666ab7609d Fix TeleBot#extract_command where the function previously would incorrectly slice /command@botname 2015-07-03 19:28:04 +02:00
0af4051dfd First implementation attempt 2015-07-03 19:22:26 +02:00
645c0b7fb4 Fix example echo bot command list bug. 2015-07-03 15:04:11 +08:00
33 changed files with 6663 additions and 452 deletions

7
.github/ISSUE_TEMPLATE vendored Normal file
View File

@ -0,0 +1,7 @@
Please answer these questions before submitting your issue. Thanks!
1. What version of pyTelegramBotAPI are you using?
2. What OS are you using?
3. What version of python are you using?

View File

@ -2,6 +2,12 @@ language: python
python:
- "2.6"
- "2.7"
- "3.3"
- "3.4"
- "3.5"
- "pypy"
- "pypy3"
install: "pip install -r requirements.txt"
script: cd tests && py.test
script:
- python setup.py install
- cd tests && py.test

619
README.md
View File

@ -1,14 +1,49 @@
# pyTelegramBotAPI
# <p align="center">pyTelegramBotAPI
A Python implementation for the Telegram Bot API.
<p align="center">A simple, but extensible Python implementation for the <a href="https://core.telegram.org/bots/api">Telegram Bot API</a>.
See [https://core.telegram.org/bots/api](https://core.telegram.org/bots/api)
[![Download Month](https://img.shields.io/pypi/v/pyTelegramBotAPI.svg)](https://pypi.python.org/pypi/pyTelegramBotAPI)
[![Build Status](https://travis-ci.org/eternnoir/pyTelegramBotAPI.svg?branch=master)](https://travis-ci.org/eternnoir/pyTelegramBotAPI)
## How to install
* [Getting started.](#getting-started)
* [Writing your first bot](#writing-your-first-bot)
* [Prerequisites](#prerequisites)
* [A simple echo bot](#a-simple-echo-bot)
* [General API Documentation](#general-api-documentation)
* [Types](#types)
* [Methods](#methods)
* [General use of the API](#general-use-of-the-api)
* [Message handlers](#message-handlers)
* [Callback Query handlers](#callback-query-handler)
* [TeleBot](#telebot)
* [Reply markup](#reply-markup)
* [Inline Mode](#inline-mode)
* [Advanced use of the API](#advanced-use-of-the-api)
* [Asynchronous delivery of messages](#asynchronous-delivery-of-messages)
* [Sending large text messages](#sending-large-text-messages)
* [Controlling the amount of Threads used by TeleBot](#controlling-the-amount-of-threads-used-by-telebot)
* [The listener mechanism](#the-listener-mechanism)
* [Using web hooks](#using-web-hooks)
* [Logging](#logging)
* [Proxy](#proxy)
* [F.A.Q.](#faq)
* [Bot 2.0](#bot-20)
* [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)
* [The Telegram Chat Group](#the-telegram-chat-group)
* [More examples](#more-examples)
* [Bots using this API](#bots-using-this-api)
Python 2 or Python 3 is required.
## Getting started.
* Install from source
This API is tested with Python 2.6, Python 2.7, Python 3.4, Pypy and Pypy 3.
There are two ways to install the library:
* Installation using pip (a Python package manager)*:
```
$ pip install pyTelegramBotAPI
```
* Installation from source (requires git):
```
$ git clone https://github.com/eternnoir/pyTelegramBotAPI.git
@ -16,92 +51,248 @@ $ cd pyTelegramBotAPI
$ python setup.py install
```
* or install with pip
It is generally recommended to use the first option.
```
$ pip install pyTelegramBotAPI
```
**While the API is production-ready, it is still under development and it has regular updates, do not forget to update it regularly by calling `pip install pytelegrambotapi --upgrade`*
## Example
## Writing your first bot
* Sending a message.
### Prerequisites
It is presumed that you [have obtained an API token with @BotFather](https://core.telegram.org/bots#botfather). We will call this token `TOKEN`.
Furthermore, you have basic knowledge of the Python programming language and more importantly [the Telegram Bot API](https://core.telegram.org/bots/api).
### A simple echo bot
The TeleBot class (defined in \__init__.py) encapsulates all API calls in a single class. It provides functions such as `send_xyz` (`send_message`, `send_document` etc.) and several ways to listen for incoming messages.
Create a file called `echo_bot.py`.
Then, open the file and create an instance of the TeleBot class.
```python
import telebot
TOKEN = '<token string>'
tb = telebot.TeleBot(TOKEN)
# tb.send_message(chatid, message)
tb.send_message(281281, 'gogo power ranger')
bot = telebot.TeleBot("TOKEN")
```
*Note: Make sure to actually replace TOKEN with your own API token.*
* Echo Bot
After that declaration, we need to register some so-called message handlers. Message handlers define filters which a message must pass. If a message passes the filter, the decorated function is called and the incoming message is passed as an argument.
Let's define a message handler which handles incoming `/start` and `/help` commands.
```python
@bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
bot.reply_to(message, "Howdy, how are you doing?")
```
A function which is decorated by a message handler __can have an arbitrary name, however, it must have only one parameter (the message)__.
Let's add another handler:
```python
@bot.message_handler(func=lambda m: True)
def echo_all(message):
bot.reply_to(message, message.text)
```
This one echoes all incoming text messages back to the sender. It uses a lambda function to test a message. If the lambda returns True, the message is handled by the decorated function. Since we want all messages to be handled by this function, we simply always return True.
*Note: all handlers are tested in the order in which they were declared*
We now have a basic bot which replies a static message to "/start" and "/help" commands and which echoes the rest of the sent messages. To start the bot, add the following to our source file:
```python
bot.polling()
```
Alright, that's it! Our source file now looks like this:
```python
import telebot
bot = telebot.TeleBot("TOKEN")
@bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
bot.reply_to(message, "Howdy, how are you doing?")
@bot.message_handler(func=lambda message: True)
def echo_all(message):
bot.reply_to(message, message.text)
bot.polling()
```
To start the bot, simply open up a terminal and enter `python echo_bot.py` to run the bot! Test it by sending commands ('/start' and '/help') and arbitrary text messages.
## General API Documentation
### Types
All types are defined in types.py. They are all completely in line with the [Telegram API's definition of the types](https://core.telegram.org/bots/api#available-types), except for the Message's `from` field, which is renamed to `from_user` (because `from` is a Python reserved token). Thus, attributes such as `message_id` can be accessed directly with `message.message_id`. Note that `message.chat` can be either an instance of `User` or `GroupChat` (see [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)).
The Message object also has a `content_type`attribute, which defines the type of the Message. `content_type` can be one of the following strings:
`text`, `audio`, `document`, `photo`, `sticker`, `video`, `video_note`, `voice`, `location`, `contact`, `new_chat_member`, `left_chat_member`, `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`, `supergroup_chat_created`, `channel_chat_created`, `migrate_to_chat_id`, `migrate_from_chat_id`, `pinned_message`.
You can use some types in one function. Example:
```content_types=["text", "sticker", "pinned_message", "photo", "audio"]```
### Methods
All [API methods](https://core.telegram.org/bots/api#available-methods) are located in the TeleBot class. They are renamed to follow common Python naming conventions. E.g. `getMe` is renamed to `get_me` and `sendMessage` to `send_message`.
### General use of the API
Outlined below are some general use cases of the API.
#### Message handlers
A message handler is a function that is decorated with the `message_handler` decorator of a TeleBot instance. Message handlers consist of one or multiple filters.
Each filter much return True for a certain message in order for a message handler to become eligible to handle that message. A message handler is declared in the following way (provided `bot` is an instance of TeleBot):
```python
@bot.message_handler(filters)
def function_name(message):
bot.reply_to(message, "This is a message handler")
```
`function_name` is not bound to any restrictions. Any function name is permitted with message handlers. The function must accept at most one argument, which will be the message that the function must handle.
`filters` is a list of keyword arguments.
A filter is declared in the following manner: `name=argument`. One handler may have multiple filters.
TeleBot supports the following filters:
|name|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)|
|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`
Here are some examples of using the filters and message handlers:
```python
import telebot
import time
bot = telebot.TeleBot("TOKEN")
TOKEN = '<token_string>'
# Handles all text messages that contains the commands '/start' or '/help'.
@bot.message_handler(commands=['start', 'help'])
def handle_start_help(message):
pass
# Handles all sent documents and audio files
@bot.message_handler(content_types=['document', 'audio'])
def handle_docs_audio(message):
pass
def listener(*messages):
"""
When new messages arrive TeleBot will call this function.
"""
for m in messages:
chatid = m.chat.id
if m.content_type == 'text':
text = m.text
tb.send_message(chatid, text)
# Handles all text messages that match the regular expression
@bot.message_handler(regexp="SOME_REGEXP")
def handle_message(message):
pass
#Handles all messages for which the lambda returns True
@bot.message_handler(func=lambda message: message.document.mime_type == 'text/plain', content_types=['document'])
def handle_text_doc(message):
pass
tb = telebot.TeleBot(TOKEN)
tb.set_update_listener(listener) #register listener
tb.polling()
#Which could also be defined as:
def test_message(message):
return message.document.mime_type == 'text/plain'
while True: # Don't let the main Thread end.
@bot.message_handler(func=test_message, content_types=['document'])
def handle_text_doc(message)
pass
# Handlers can be stacked to create a function which will be called if either message_handler is eligible
# This handler will be called if the message starts with '/hello' OR is some emoji
@bot.message_handler(commands=['hello'])
@bot.message_handler(func=lambda msg: msg.text.encode("utf-8") == SOME_FANCY_EMOJI)
def send_something(message):
pass
```
**Important: all handlers are tested in the order in which they were declared**
## TeleBot API usage
#### Edited Message handlers
Same as Message handlers
#### channel_post_handler
Same as Message handlers
#### edited_channel_post_handler
Same as Message handlers
#### 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.
```python
@bot.callback_query_handler(func=lambda call: True)
def test_callback(call):
logger.info(call)
```
#### TeleBot
```python
import telebot
import time
TOKEN = '<token_string>'
tb = telebot.TeleBot(TOKEN) #create a new Telegram Bot object
# Upon calling this function, TeleBot starts polling the Telegram servers for new messages.
# - none_stop: True/False (default False) - Don't stop polling when receiving an error from the Telegram servers
# - interval: True/False (default False) - The interval between polling requests
# Note: Editing this parameter harms the bot's response time
# - timeout: integer (default 20) - Timeout in seconds for long polling.
tb.polling(none_stop=False, interval=0, timeout=20)
# getMe
user = tb.get_me()
# setWebhook
tb.set_webhook(url="http://example.com", certificate=open('mycert.pem'))
# unset webhook
tb.remove_webhook()
# getUpdates
updates = tb.get_updates()
updates = tb.get_updates(1234,100,20) #get_Updates(offset, limit, timeout):
# sendMessage
tb.send_message(chatid, text)
# forwardMessage
# tb.forward_message(10894,926,3)
tb.forward_message(to_chat_id, from_chat_id, message_id)
# All send_xyz functions which can take a file as an argument, can also take a file_id instead of a file.
# sendPhoto
photo = open('/tmp/photo.png', 'rb')
tb.send_photo(chat_id, photo)
tb.send_photo(chat_id, "FILEID")
# sendAudio
audio = open('/tmp/audio.ogg', 'rb')
audio = open('/tmp/audio.mp3', 'rb')
tb.send_audio(chat_id, audio)
tb.send_audio(chat_id, "FILEID")
## sendAudio with duration, performer and title.
tb.send_audio(CHAT_ID, file_data, 1, 'eternnoir', 'pyTelegram')
# sendVoice
voice = open('/tmp/voice.ogg', 'rb')
tb.send_voice(chat_id, voice)
tb.send_voice(chat_id, "FILEID")
# sendDocument
doc = open('/tmp/file.txt', 'rb')
tb.send_document(chat_id, doc)
tb.send_document(chat_id, "FILEID")
# sendSticker
sti = open('/tmp/sti.webp', 'rb')
tb.send_sticker(chat_id, sti)
tb.send_sticker(chat_id, "FILEID")
# sendVideo
video = open('/tmp/video.mp4', 'rb')
tb.send_video(chat_id, video)
tb.send_video(chat_id, "FILEID")
# sendVideoNote
videonote = open('/tmp/videonote.mp4', 'rb')
tb.send_video(chat_id, videonote)
tb.send_video(chat_id, "FILEID")
# sendLocation
tb.send_location(chat_id, lat, lon)
@ -111,123 +302,283 @@ tb.send_location(chat_id, lat, lon)
# 'record_audio', 'upload_audio', 'upload_document' or 'find_location'.
tb.send_chat_action(chat_id, action_string)
# Use the ReplyKeyboardMarkup class.
# Thanks pevdh.
# getFile
# Downloading a file is straightforward
# Returns a File object
import requests
file_info = tb.get_file(file_id)
file = requests.get('https://api.telegram.org/file/bot{0}/{1}'.format(API_TOKEN, file_info.file_path))
```
#### Reply markup
All `send_xyz` functions of TeleBot take an optional `reply_markup` argument. This argument must be an instance of `ReplyKeyboardMarkup`, `ReplyKeyboardRemove` or `ForceReply`, which are defined in types.py.
```python
from telebot import types
markup = types.ReplyKeyboardMarkup()
markup.add('a', 'v', 'd')
tb.send_message(chat_id, message, reply_markup=markup)
# Using the ReplyKeyboardMarkup class
# It's constructor can take the following optional arguments:
# - resize_keyboard: True/False (default False)
# - one_time_keyboard: True/False (default False)
# - selective: True/False (default False)
# - row_width: integer (default 3)
# row_width is used in combination with the add() function.
# It defines how many buttons are fit on each row before continuing on the next row.
markup = types.ReplyKeyboardMarkup(row_width=2)
itembtn1 = types.KeyboardButton('a')
itembtn2 = types.KeyboardButton('v')
itembtn3 = types.KeyboardButton('d')
markup.add(itembtn1, itembtn2, itembtn3)
tb.send_message(chat_id, "Choose one letter:", reply_markup=markup)
# or add strings one row at a time:
# or add KeyboardButton one row at a time:
markup = types.ReplyKeyboardMarkup()
markup.row('a', 'v')
markup.row('c', 'd', 'e')
tb.send_message(chat_id, message, reply_markup=markup)
itembtna = types.KeyboardButton('a')
itembtnv = types.KeyboardButton('v')
itembtnc = types.KeyboardButton('c')
itembtnd = types.KeyboardButton('d')
itembtne = types.KeyboardButton('e')
markup.row(itembtna, itembtnv)
markup.row(itembtnc, itembtnd, itembtne)
tb.send_message(chat_id, "Choose one letter:", reply_markup=markup)
```
The last example yields this result:
![ReplyKeyboardMarkup](https://farm3.staticflickr.com/2933/32418726704_9ef76093cf_o_d.jpg "ReplyKeyboardMarkup")
```python
# ReplyKeyboardRemove: hides a previously sent ReplyKeyboardMarkup
# Takes an optional selective argument (True/False, default False)
markup = types.ReplyKeyboardRemove(selective=False)
tb.send_message(chat_id, message, reply_markup=markup)
```
## Creating a Telegram bot with the pyTelegramBotAPI
There are two ways to define a Telegram Bot with the pyTelegramBotAPI.
```python
# ForceReply: forces a user to reply to a message
# Takes an optional selective argument (True/False, default False)
markup = types.ForceReply(selective=False)
tb.send_message(chat_id, "Send me another word:", reply_markup=markup)
```
ForceReply:
![ForceReply](https://farm4.staticflickr.com/3809/32418726814_d1baec0fc2_o_d.jpg "ForceReply")
### Inline Mode
More information about [Inline mode](https://core.telegram.org/bots/inline).
#### inline_handler
Now, you can use inline_handler to get inline_query in telebot.
```python
@bot.inline_handler(lambda query: query.query == 'text')
def query_text(inline_query):
# Query message is text
```
#### chosen_inline_handler
Use chosen_inline_handler to get chosen_inline_result in telebot. Don't forgot add the /setinlinefeedback
command for @Botfather.
More information : [collecting-feedback](https://core.telegram.org/bots/inline#collecting-feedback)
```python
@bot.chosen_inline_handler(func=lambda chosen_inline_result: True)
def test_chosen(chosen_inline_result):
# Process all chosen_inline_result.
```
#### answer_inline_query
```python
@bot.inline_handler(lambda query: query.query == 'text')
def query_text(inline_query):
try:
r = types.InlineQueryResultArticle('1', 'Result', types.InputTextMessageContent('Result message.'))
r2 = types.InlineQueryResultArticle('2', 'Result2', types.InputTextMessageContent('Result message2.'))
bot.answer_inline_query(inline_query.id, [r, r2])
except Exception as e:
print(e)
```
### Working with entities:
This object represents one special entity in a text message. For example, hashtags, usernames, URLs, etc.
Attributes:
* `type`
* `url`
* `offset`
* `length`
* `user`
**Here's an Example:**`message.entities[num].<attribute>`<br>
Here `num` is the entity number or order of entity in a reply, for if incase there are multiple entities in the reply/message.<br>
`message.entities` returns a list of entities object. <br>
`message.entities[0].type` would give the type of the first entity<br>
Refer [Bot Api](https://core.telegram.org/bots/api#messageentity) for extra details
## Advanced use of the API
### Asynchronous delivery of messages
There exists an implementation of TeleBot which executes all `send_xyz` and the `get_me` functions asynchronously. This can speed up you bot __significantly__, but it has unwanted side effects if used without caution.
To enable this behaviour, create an instance of AsyncTeleBot instead of TeleBot.
```python
tb = telebot.AsyncTeleBot("TOKEN")
```
Now, every function that calls the Telegram API is executed in a separate Thread. The functions are modified to return an AsyncTask instance (defined in util.py). Using AsyncTeleBot allows you to do the following:
```python
import telebot
tb = telebot.AsyncTeleBot("TOKEN")
task = tb.get_me() # Execute an API call
# Do some other operations...
a = 0
for a in range(100):
a += 10
result = task.wait() # Get the result of the execution
```
*Note: if you execute send_xyz functions after eachother without calling wait(), the order in which messages are delivered might be wrong.*
### Sending large text messages
Sometimes you must send messages that exceed 5000 characters. The Telegram API can not handle that many characters in one request, so we need to split the message in multiples. Here is how to do that using the API:
```python
from telebot import util
large_text = open("large_text.txt", "rb").read()
# Split the text each 3000 characters.
# split_string returns a list with the splitted text.
splitted_text = util.split_string(large_text, 3000)
for text in splitted_text:
tb.send_message(chat_id, text)
```
### Controlling the amount of Threads used by TeleBot
The TeleBot constructor takes the following optional arguments:
- threaded: True/False (default True). A flag to indicate whether
TeleBot should execute message handlers on it's polling Thread.
### The listener mechanism
* First, create a TeleBot instance.
As an alternative to the message handlers, one can also register a function as a listener to TeleBot. Example:
```python
import telebot
def handle_messages(messages):
for message in messages:
# Do something with the message
bot.reply_to(message, 'Hi')
TOKEN = '<token string>'
bot = telebot.TeleBot(TOKEN)
```
* Then, define a listener function.
```python
def echo_messages(*messages):
"""
Echoes all incoming messages of content_type 'text'.
"""
for m in messages:
chatid = m.chat.id
if m.content_type == 'text':
text = m.text
bot.send_message(chatid, text)
```
* Now, register your listener with the TeleBot instance and call TeleBot#polling()
```python
bot.set_update_listener(echo_messages)
bot.set_update_listener(handle_messages)
bot.polling()
while True: # Don't let the main Thread end.
pass
```
* use Message's content_type attribute to check the type of Message. Now Message supports content types:
* text
* audio
* document
* photo
* sticker
* video
* location
* contact
* new_chat_participant
* left_chat_participant
* new_chat_title
* new_chat_photo
* delete_chat_photo
* group_chat_created
* That's it!
### The decorator mechanism
* First, create a TeleBot instance.
### Using web hooks
When using webhooks telegram sends one Update per call, for processing it you should call process_new_messages([update.message]) when you recieve it.
There are some examples using webhooks in the *examples/webhook_examples* directory.
### Logging
You can use the Telebot module logger to log debug info about Telebot. Use `telebot.logger` to get the logger of the TeleBot module.
It is possible to add custom logging Handlers to the logger. Refer to the [Python logging module page](https://docs.python.org/2/library/logging.html) for more info.
```python
import telebot
import logging
TOKEN = '<token string>'
bot = telebot.TeleBot(TOKEN)
logger = telebot.logger
telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console.
```
* Next, define all of your so-called message handlers and decorate them with @bot.message_handler
### Proxy
You can use proxy for request. `apihelper.proxy` object will use by call `requests` proxies argument.
```python
# Handle /start and /help
@bot.message_handler(commands=['start', 'help'])
def command_help(message):
bot.reply_to(message, "Hello, did someone call for help?")
# Handles all messages which text matches the regex regexp.
# See https://en.wikipedia.org/wiki/Regular_expression
# This regex matches all sent url's.
@bot.message_handler(regexp='((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)')
def command_url(message):
bot.reply_to(message, "I shouldn't open that url, should I?")
from telebot import apihelper
# Handle all sent documents of type 'text/plain'.
@bot.message_handler(func=lambda message: message.document.mime_type == 'text/plain', content_types=['document'])
def command_handle_document(message):
bot.reply_to(message, "Document received, sir!")
# Default command handler. A lambda expression which always returns True is used for this purpose.
@bot.message_handler(func=lambda message: True, content_types=['audio', 'video', 'document', 'text', 'location', 'contact', 'sticker'])
def default_command(message):
bot.reply_to(message, "This is the default command handler.")
apihelper.proxy = {'http', 'http://10.10.1.10:3128'}
```
* And finally, call bot.polling()
If you want to use socket5 proxy you need install dependency `pip install requests[socks]`.
```python
bot.polling()
while True: # Don't end the main thread.
pass
proxies = {
'http': 'socks5://user:pass@host:port',
'https': 'socks5://user:pass@host:port'
}
```
Use whichever mechanism fits your purpose! It is even possible to mix and match.
## TODO
- [x] getMe
- [x] sendMessage
- [x] forwardMessage
- [x] sendPhoto
- [x] sendAudio
- [x] sendDocument
- [x] sendSticker
- [x] sendVideo
- [x] sendLocation
- [x] sendChatAction
- [x] getUserProfilePhotos
- [x] getUpdate
## F.A.Q.
### Bot 2.0
April 9,2016 Telegram release new bot 2.0 API, which has a drastic revision especially for the change of method's interface.If you want to update to the latest version, please make sure you've switched bot's code to bot 2.0 method interface.
[More information about pyTelegramBotAPI support bot2.0](https://github.com/eternnoir/pyTelegramBotAPI/issues/130)
### How can I distinguish a User and a GroupChat in message.chat?
Telegram Bot API support new type Chat for message.chat.
- Check the ```type``` attribute in ```Chat``` object:
-
```python
if message.chat.type == “private”:
# private chat message
if message.chat.type == “group”:
# group chat message
if message.chat.type == “supergroup”:
# supergroup chat message
if message.chat.type == “channel”:
# channel message
```
## The Telegram Chat Group
Get help. Discuss. Chat.
* Join the [pyTelegramBotAPI Telegram Chat Group](https://telegram.me/joinchat/Bn4ixj84FIZVkwhk2jag6A)
* We now have a Telegram Channel as well! Keep yourself up to date with API changes, and [join it](https://telegram.me/pytelegrambotapi).
## More examples
* [Echo Bot](https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/echo_bot.py)
* [Deep Linking](https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/deep_linking.py)
* [next_step_handler Example](https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/step_example.py)
## Bots using this API
* [SiteAlert bot](https://telegram.me/SiteAlert_bot) ([source](https://github.com/ilteoood/SiteAlert-Python)) by *ilteoood* - Monitors websites and sends a notification on changes
* [TelegramLoggingBot](https://github.com/aRandomStranger/TelegramLoggingBot) by *aRandomStranger*
* [Send to Kindle Bot](https://telegram.me/Send2KindleBot) by *GabrielRF* - Send to Kindle files or links to files.
* [Telegram LMGTFY_bot](https://github.com/GabrielRF/telegram-lmgtfy_bot) ([source](https://github.com/GabrielRF/telegram-lmgtfy_bot)) by *GabrielRF* - Let me Google that for you.
* [Telegram UrlProBot](https://github.com/GabrielRF/telegram-urlprobot) ([source](https://github.com/GabrielRF/telegram-urlprobot)) by *GabrielRF* - URL shortener and URL expander.
* [Telegram Proxy Bot](https://bitbucket.org/master_groosha/telegram-proxy-bot) by *Groosha* - A simple BITM (bot-in-the-middle) for Telegram acting as some kind of "proxy".
* [Telegram Proxy Bot](https://github.com/mrgigabyte/proxybot) by *mrgigabyte* - `Credits for the original version of this bot goes to` **Groosha** `, simply added certain features which I thought were needed`.
* [RadRetroRobot](https://github.com/Tronikart/RadRetroRobot) by *Tronikart* - Multifunctional Telegram Bot RadRetroRobot.
* [League of Legends bot](https://telegram.me/League_of_Legends_bot) ([source](https://github.com/i32ropie/lol)) by *i32ropie*
* [NeoBot](https://github.com/neoranger/NeoBot) by *neoranger*
* [TagAlertBot](https://github.com/pitasi/TagAlertBot) by *pitasi*
* [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.
* [TheZigZagProject](https://github.com/WebShark025/TheZigZagProject) - The 'All In One' bot for Telegram! by WebShark025
* [proxybot](https://github.com/p-hash/proxybot) - Simple Proxy Bot for Telegram. by p-hash
* [DonantesMalagaBot](https://github.com/vfranch/DonantesMalagaBot)- DonantesMalagaBot facilitates information to Malaga blood donors about the places where they can donate today or in the incoming days. It also records the date of the last donation so that it helps the donors to know when they can donate again. - by vfranch
* [DuttyBot](https://github.com/DmytryiStriletskyi/DuttyBot) by *Dmytryi Striletskyi* - Timetable for one university in Kiev.
* [dailypepebot](https://telegram.me/dailypepebot) by [*Jaime*](https://github.com/jiwidi/Dailypepe) - Get's you random pepe images and gives you their id, then you can call this image with the number.
* [DailyQwertee](https://t.me/DailyQwertee) by [*Jaime*](https://github.com/jiwidi/DailyQwertee) - Bot that manages a channel that sends qwertee daily tshirts every day at 00:00
* [wat-bridge](https://github.com/rmed/wat-bridge) by [*rmed*](https://github.com/rmed) - Send and receive messages to/from WhatsApp through Telegram
* [flibusta_bot](https://github.com/Kurbezz/flibusta_bot) by [*Kurbezz*](https://github.com/Kurbezz)
* [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.
Want to have your bot listed here? Send a Telegram message to @eternnoir or @pevdh.

807
README.rst Normal file
View File

@ -0,0 +1,807 @@
#
.. raw:: html
<p align="center">
pyTelegramBotAPI
.. raw:: html
<p align="center">
A simple, but extensible Python implementation for the `Telegram Bot
API <https://core.telegram.org/bots/api>`__.
|Download Month| |Build Status| |Download Month|
- `Getting started. <#getting-started>`__
- `Writing your first bot <#writing-your-first-bot>`__
- `Prerequisites <#prerequisites>`__
- `A simple echo bot <#a-simple-echo-bot>`__
- `General API Documentation <#general-api-documentation>`__
- `Types <#types>`__
- `Methods <#methods>`__
- `General use of the API <#general-use-of-the-api>`__
- `Message handlers <#message-handlers>`__
- `Callback Query handlers <#callback-query-handler>`__
- `TeleBot <#telebot>`__
- `Reply markup <#reply-markup>`__
- `Inline Mode <#inline-mode>`__
- `Advanced use of the API <#advanced-use-of-the-api>`__
- `Asynchronous delivery of
messages <#asynchronous-delivery-of-messages>`__
- `Sending large text messages <#sending-large-text-messages>`__
- `Controlling the amount of Threads used by
TeleBot <#controlling-the-amount-of-threads-used-by-telebot>`__
- `The listener mechanism <#the-listener-mechanism>`__
- `Using web hooks <#using-web-hooks>`__
- `Logging <#logging>`__
- `F.A.Q. <#faq>`__
- `Bot 2.0 <#bot-20>`__
- `How can I distinguish a User and a GroupChat in
message.chat? <#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat>`__
- `The Telegram Chat Group <#the-telegram-chat-group>`__
- `More examples <#more-examples>`__
- `Bots using this API <#bots-using-this-api>`__
Getting started.
----------------
This API is tested with Python 2.6, Python 2.7, Python 3.4, Pypy and
Pypy 3. There are two ways to install the library:
- Installation using pip (a Python package manager)\*:
::
$ pip install pyTelegramBotAPI
- Installation from source (requires git):
::
$ git clone https://github.com/eternnoir/pyTelegramBotAPI.git
$ cd pyTelegramBotAPI
$ python setup.py install
It is generally recommended to use the first option.
\*\*While the API is production-ready, it is still under development and
it has regular updates, do not forget to update it regularly by calling
``pip install pytelegrambotapi --upgrade``\ \*
Writing your first bot
----------------------
Prerequisites
~~~~~~~~~~~~~
It is presumed that you [have obtained an API token with
@BotFather](https://core.telegram.org/bots#botfather). We will call this
token ``TOKEN``. Furthermore, you have basic knowledge of the Python
programming language and more importantly `the Telegram Bot
API <https://core.telegram.org/bots/api>`__.
A simple echo bot
~~~~~~~~~~~~~~~~~
The TeleBot class (defined in \_\_init\_\_.py) encapsulates all API
calls in a single class. It provides functions such as ``send_xyz``
(``send_message``, ``send_document`` etc.) and several ways to listen
for incoming messages.
Create a file called ``echo_bot.py``. Then, open the file and create an
instance of the TeleBot class.
.. code:: python
import telebot
bot = telebot.TeleBot("TOKEN")
*Note: Make sure to actually replace TOKEN with your own API token.*
After that declaration, we need to register some so-called message
handlers. Message handlers define filters which a message must pass. If
a message passes the filter, the decorated function is called and the
incoming message is passed as an argument.
Let's define a message handler which handles incoming ``/start`` and
``/help`` commands.
.. code:: python
@bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
bot.reply_to(message, "Howdy, how are you doing?")
A function which is decorated by a message handler **can have an
arbitrary name, however, it must have only one parameter (the
message)**.
Let's add another handler:
.. code:: python
@bot.message_handler(func=lambda m: True)
def echo_all(message):
bot.reply_to(message, message.text)
This one echoes all incoming text messages back to the sender. It uses a
lambda function to test a message. If the lambda returns True, the
message is handled by the decorated function. Since we want all messages
to be handled by this function, we simply always return True.
*Note: all handlers are tested in the order in which they were declared*
We now have a basic bot which replies a static message to "/start" and
"/help" commands and which echoes the rest of the sent messages. To
start the bot, add the following to our source file:
.. code:: python
bot.polling()
Alright, that's it! Our source file now looks like this:
.. code:: python
import telebot
bot = telebot.TeleBot("TOKEN")
@bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
bot.reply_to(message, "Howdy, how are you doing?")
@bot.message_handler(func=lambda message: True)
def echo_all(message):
bot.reply_to(message, message.text)
bot.polling()
To start the bot, simply open up a terminal and enter
``python echo_bot.py`` to run the bot! Test it by sending commands
('/start' and '/help') and arbitrary text messages.
General API Documentation
-------------------------
Types
~~~~~
All types are defined in types.py. They are all completely in line with
the `Telegram API's definition of the
types <https://core.telegram.org/bots/api#available-types>`__, except
for the Message's ``from`` field, which is renamed to ``from_user``
(because ``from`` is a Python reserved token). Thus, attributes such as
``message_id`` can be accessed directly with ``message.message_id``.
Note that ``message.chat`` can be either an instance of ``User`` or
``GroupChat`` (see `How can I distinguish a User and a GroupChat in
message.chat? <#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat>`__).
The Message object also has a ``content_types``\ attribute, which
defines the type of the Message. ``content_types`` can be one of the
following strings: 'text', 'audio', 'document', 'photo', 'sticker',
'video', 'voice', 'location', 'contact', 'new\_chat\_participant',
'left\_chat\_participant', 'new\_chat\_title', 'new\_chat\_photo',
'delete\_chat\_photo', 'group\_chat\_created'.
Methods
~~~~~~~
All `API
methods <https://core.telegram.org/bots/api#available-methods>`__ are
located in the TeleBot class. They are renamed to follow common Python
naming conventions. E.g. ``getMe`` is renamed to ``get_me`` and
``sendMessage`` to ``send_message``.
General use of the API
~~~~~~~~~~~~~~~~~~~~~~
Outlined below are some general use cases of the API.
Message handlers
^^^^^^^^^^^^^^^^
A message handler is a function that is decorated with the
``message_handler`` decorator of a TeleBot instance. Message handlers
consist of one or multiple filters. Each filter much return True for a
certain message in order for a message handler to become eligible to
handle that message. A message handler is declared in the following way
(provided ``bot`` is an instance of TeleBot):
.. code:: python
@bot.message_handler(filters)
def function_name(message):
bot.reply_to(message, "This is a message handler")
``function_name`` is not bound to any restrictions. Any function name is
permitted with message handlers. The function must accept at most one
argument, which will be the message that the function must handle.
``filters`` is a list of keyword arguments. A filter is declared in the
following manner: ``name=argument``. One handler may have multiple
filters. TeleBot supports the following filters:
+--------+------+------+
| name | argu | Cond |
| | ment | itio |
| | (s) | n |
+========+======+======+
| conten | list | ``Tr |
| t\_typ | of | ue`` |
| es | stri | if |
| | ngs | mess |
| | (def | age. |
| | ault | cont |
| | ``[' | ent\ |
| | text | _typ |
| | ']`` | e |
| | ) | is |
| | | in |
| | | the |
| | | list |
| | | of |
| | | stri |
| | | ngs. |
+--------+------+------+
| regexp | a | ``Tr |
| | regu | ue`` |
| | lar | if |
| | expr | ``re |
| | essi | .sea |
| | on | rch( |
| | as a | rege |
| | stri | xp_a |
| | ng | rg)` |
| | | ` |
| | | retu |
| | | rns |
| | | ``Tr |
| | | ue`` |
| | | and |
| | | ``me |
| | | ssag |
| | | e.co |
| | | nten |
| | | t_ty |
| | | pe = |
| | | = 't |
| | | ext' |
| | | `` |
| | | (See |
| | | `Pyt |
| | | hon |
| | | Regu |
| | | lar |
| | | Expr |
| | | essi |
| | | ons |
| | | <htt |
| | | ps:/ |
| | | /doc |
| | | s.py |
| | | thon |
| | | .org |
| | | /2/l |
| | | ibra |
| | | ry/r |
| | | e.ht |
| | | ml>` |
| | | __ |
+--------+------+------+
| comman | list | ``Tr |
| ds | of | ue`` |
| | stri | if |
| | ngs | ``me |
| | | ssag |
| | | e.co |
| | | nten |
| | | t_ty |
| | | pe = |
| | | = 't |
| | | ext' |
| | | `` |
| | | and |
| | | ``me |
| | | ssag |
| | | e.te |
| | | xt`` |
| | | star |
| | | ts |
| | | with |
| | | a |
| | | comm |
| | | and |
| | | that |
| | | is |
| | | in |
| | | the |
| | | list |
| | | of |
| | | stri |
| | | ngs. |
+--------+------+------+
| func | a | ``Tr |
| | func | ue`` |
| | tion | if |
| | (lam | the |
| | bda | lamb |
| | or | da |
| | func | or |
| | tion | func |
| | refe | tion |
| | renc | refe |
| | e) | renc |
| | | e |
| | | retu |
| | | rns |
| | | ``Tr |
| | | ue`` |
+--------+------+------+
Here are some examples of using the filters and message handlers:
.. code:: python
import telebot
bot = telebot.TeleBot("TOKEN")
# Handles all text messages that contains the commands '/start' or '/help'.
@bot.message_handler(commands=['start', 'help'])
def handle_start_help(message):
pass
# Handles all sent documents and audio files
@bot.message_handler(content_types=['document', 'audio'])
def handle_docs_audio(message):
pass
# Handles all text messages that match the regular expression
@bot.message_handler(regexp="SOME_REGEXP")
def handle_message(message):
pass
#Handles all messages for which the lambda returns True
@bot.message_handler(func=lambda message: message.document.mime_type == 'text/plain', content_types=['document'])
def handle_text_doc(message):
pass
#Which could also be defined as:
def test_message(message):
return message.document.mime_type == 'text/plan'
@bot.message_handler(func=test_message, content_types=['document'])
def handle_text_doc(message)
pass
# Handlers can be stacked to create a function which will be called if either message_handler is eligible
# This handler will be called if the message starts with '/hello' OR is some emoji
@bot.message_handler(commands=['hello'])
@bot.message_handler(func=lambda msg: msg.text.encode("utf-8") == SOME_FANCY_EMOJI)
def send_something(message):
pass
**Important: all handlers are tested in the order in which they were
declared**
Callback Query Handler
^^^^^^^^^^^^^^^^^^^^^^
In bot2.0 update. You can get ``callback_query`` in update object. In
telebot use ``callback_query_handler`` to process callback\_querys.
.. code:: python
@bot.callback_query_handler(func=lambda call: True)
def test_callback(call):
logger.info(call)
TeleBot
^^^^^^^
.. code:: python
import telebot
TOKEN = '<token_string>'
tb = telebot.TeleBot(TOKEN) #create a new Telegram Bot object
# Upon calling this function, TeleBot starts polling the Telegram servers for new messages.
# - none_stop: True/False (default False) - Don't stop polling when receiving an error from the Telegram servers
# - interval: True/False (default False) - The interval between polling requests
# Note: Editing this parameter harms the bot's response time
# - timeout: integer (default 20) - Timeout in seconds for long polling.
tb.polling(none_stop=False, interval=0, timeout=20)
# getMe
user = tb.get_me()
# setWebhook
tb.set_webhook(url="http://example.com", certificate=open('mycert.pem'))
# unset webhook
tb.remove_webhook()
# getUpdates
updates = tb.get_updates()
updates = tb.get_updates(1234,100,20) #get_Updates(offset, limit, timeout):
# sendMessage
tb.send_message(chatid, text)
# forwardMessage
tb.forward_message(to_chat_id, from_chat_id, message_id)
# All send_xyz functions which can take a file as an argument, can also take a file_id instead of a file.
# sendPhoto
photo = open('/tmp/photo.png', 'rb')
tb.send_photo(chat_id, photo)
tb.send_photo(chat_id, "FILEID")
# sendAudio
audio = open('/tmp/audio.mp3', 'rb')
tb.send_audio(chat_id, audio)
tb.send_audio(chat_id, "FILEID")
## sendAudio with duration, performer and title.
tb.send_audio(CHAT_ID, file_data, 1, 'eternnoir', 'pyTelegram')
# sendVoice
voice = open('/tmp/voice.ogg', 'rb')
tb.send_voice(chat_id, voice)
tb.send_voice(chat_id, "FILEID")
# sendDocument
doc = open('/tmp/file.txt', 'rb')
tb.send_document(chat_id, doc)
tb.send_document(chat_id, "FILEID")
# sendSticker
sti = open('/tmp/sti.webp', 'rb')
tb.send_sticker(chat_id, sti)
tb.send_sticker(chat_id, "FILEID")
# sendVideo
video = open('/tmp/video.mp4', 'rb')
tb.send_video(chat_id, video)
tb.send_video(chat_id, "FILEID")
# sendLocation
tb.send_location(chat_id, lat, lon)
# sendChatAction
# action_string can be one of the following strings: 'typing', 'upload_photo', 'record_video', 'upload_video',
# 'record_audio', 'upload_audio', 'upload_document' or 'find_location'.
tb.send_chat_action(chat_id, action_string)
# getFile
# Downloading a file is straightforward
# Returns a File object
import requests
file_info = tb.get_file(file_id)
file = requests.get('https://api.telegram.org/file/bot{0}/{1}'.format(API_TOKEN, file_info.file_path))
Reply markup
^^^^^^^^^^^^
All ``send_xyz`` functions of TeleBot take an optional ``reply_markup``
argument. This argument must be an instance of ``ReplyKeyboardMarkup``,
``ReplyKeyboardRemove`` or ``ForceReply``, which are defined in types.py.
.. code:: python
from telebot import types
# Using the ReplyKeyboardMarkup class
# It's constructor can take the following optional arguments:
# - resize_keyboard: True/False (default False)
# - one_time_keyboard: True/False (default False)
# - selective: True/False (default False)
# - row_width: integer (default 3)
# row_width is used in combination with the add() function.
# It defines how many buttons are fit on each row before continuing on the next row.
markup = types.ReplyKeyboardMarkup(row_width=2)
itembtn1 = types.KeyboardButton('a')
itembtn2 = types.KeyboardButton('v')
itembtn3 = types.KeyboardButton('d')
markup.add(itembtn1, itembtn2, itembtn3)
tb.send_message(chat_id, "Choose one letter:", reply_markup=markup)
# or add strings one row at a time:
markup = types.ReplyKeyboardMarkup()
itembtna = types.KeyboardButton('a')
itembtnv = types.KeyboardButton('v')
itembtnc = types.KeyboardButton('c')
itembtnd = types.KeyboardButton('d')
itembtne = types.KeyboardButton('e')
markup.row(itembtna, itembtnv)
markup.row(itembtnc, itembtnd, itembtne)
tb.send_message(chat_id, "Choose one letter:", reply_markup=markup)
The last example yields this result:
.. figure:: https://pp.vk.me/c624430/v624430512/473e5/_mxxW7FPe4U.jpg
:alt: ReplyKeyboardMarkup
ReplyKeyboardMarkup
.. code:: python
# ReplyKeyboardRemove: hides a previously sent ReplyKeyboardMarkup
# Takes an optional selective argument (True/False, default False)
markup = types.ReplyKeyboardRemove(selective=False)
tb.send_message(chat_id, message, reply_markup=markup)
.. code:: python
# ForceReply: forces a user to reply to a message
# Takes an optional selective argument (True/False, default False)
markup = types.ForceReply(selective=False)
tb.send_message(chat_id, "Send me another word:", reply_markup=markup)
ForceReply:
.. figure:: https://pp.vk.me/c624430/v624430512/473ec/602byyWUHcs.jpg
:alt: ForceReply
ForceReply
Inline Mode
~~~~~~~~~~~
More information about `Inline
mode <https://core.telegram.org/bots/inline>`__.
inline\_handler
^^^^^^^^^^^^^^^
Now, you can use inline\_handler to get inline\_query in telebot.
.. code:: python
@bot.inline_handler(lambda query: query.query == 'text')
def query_text(inline_query):
# Query message is text
chosen\_inline\_handler
^^^^^^^^^^^^^^^^^^^^^^^
Use chosen\_inline\_handler to get chosen\_inline\_result in telebot.
Don't forgot add the /setinlinefeedback command for @Botfather.
More information :
`collecting-feedback <https://core.telegram.org/bots/inline#collecting-feedback>`__
.. code:: python
@bot.chosen_inline_handler(func=lambda chosen_inline_result: True)
def test_chosen(chosen_inline_result):
# Process all chosen_inline_result.
answer\_inline\_query
^^^^^^^^^^^^^^^^^^^^^
.. code:: python
@bot.inline_handler(lambda query: query.query == 'text')
def query_text(inline_query):
try:
r = types.InlineQueryResultArticle('1', 'Result', 'Result message.')
r2 = types.InlineQueryResultArticle('2', 'Result2', 'Result message2.')
bot.answer_inline_query(inline_query.id, [r, r2])
except Exception as e:
print(e)
Advanced use of the API
-----------------------
Asynchronous delivery of messages
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There exists an implementation of TeleBot which executes all
``send_xyz`` and the ``get_me`` functions asynchronously. This can speed
up you bot **significantly**, but it has unwanted side effects if used
without caution. To enable this behaviour, create an instance of
AsyncTeleBot instead of TeleBot.
.. code:: python
tb = telebot.AsyncTeleBot("TOKEN")
Now, every function that calls the Telegram API is executed in a
separate Thread. The functions are modified to return an AsyncTask
instance (defined in util.py). Using AsyncTeleBot allows you to do the
following:
.. code:: python
import telebot
tb = telebot.AsyncTeleBot("TOKEN")
task = tb.get_me() # Execute an API call
# Do some other operations...
a = 0
for a in range(100):
a += 10
result = task.wait() # Get the result of the execution
*Note: if you execute send\_xyz functions after eachother without
calling wait(), the order in which messages are delivered might be
wrong.*
Sending large text messages
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sometimes you must send messages that exceed 5000 characters. The
Telegram API can not handle that many characters in one request, so we
need to split the message in multiples. Here is how to do that using the
API:
.. code:: python
from telebot import util
large_text = open("large_text.txt", "rb").read()
# Split the text each 3000 characters.
# split_string returns a list with the splitted text.
splitted_text = util.split_string(large_text, 3000)
for text in splitted_text:
tb.send_message(chat_id, text)
Controlling the amount of Threads used by TeleBot
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The TeleBot constructor takes the following optional arguments:
- create\_threads: True/False (default True). A flag to indicate
whether TeleBot should execute message handlers on it's polling
Thread.
- num\_threads: integer (default 4). Controls the amount of
WorkerThreads created for the internal thread pool that TeleBot uses
to execute message handlers. Is not used when create\_threads is
False.
The listener mechanism
~~~~~~~~~~~~~~~~~~~~~~
As an alternative to the message handlers, one can also register a
function as a listener to TeleBot. Example:
.. code:: python
def handle_messages(messages):
for message in messsages:
# Do something with the message
bot.reply_to(message, 'Hi')
bot.set_update_listener(handle_messages)
bot.polling()
Using webhooks
~~~~~~~~~~~~~~
When using webhooks telegram sends one Update per call, for processing
it you should call process\_new\_messages([update.message]) when you
recieve it.
There are some examples using webhooks in the
*examples/webhook\_examples* directory.
Logging
~~~~~~~
You can use the Telebot module logger to log debug info about Telebot.
Use ``telebot.logger`` to get the logger of the TeleBot module. It is
possible to add custom logging Handlers to the logger. Refer to the
`Python logging module
page <https://docs.python.org/2/library/logging.html>`__ for more info.
.. code:: python
import logging
logger = telebot.logger
telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console.
F.A.Q.
------
Bot 2.0
~~~~~~~
April 9,2016 Telegram release new bot 2.0 API, which has a drastic
revision especially for the change of method's interface.If you want to
update to the latest version, please make sure you've switched bot's
code to bot 2.0 method interface.
`More information about pyTelegramBotAPI support
bot2.0 <https://github.com/eternnoir/pyTelegramBotAPI/issues/130>`__
How can I distinguish a User and a GroupChat in message.chat?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Telegram Bot API support new type Chat for message.chat.
- Check the ``type`` attribute in ``Chat`` object:
- \`\`\`python if message.chat.type == “private”: # private chat
message
if message.chat.type == “group”: # group chat message
if message.chat.type == “supergroup”: # supergroup chat message
if message.chat.type == “channel”: # channel message
\`\`\`
The Telegram Chat Group
-----------------------
Get help. Discuss. Chat.
- Join the pyTelegramBotAPI Telegram Chat Group
- Messge to @eternnoir by telegram for Invitation.
- We now have a Telegram Channel as well! Keep yourself up to date with
API changes, and `join it <https://telegram.me/pytelegrambotapi>`__.
More examples
-------------
- `Echo
Bot <https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/echo_bot.py>`__
- `Deep
Linking <https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/deep_linking.py>`__
- `next\_step\_handler
Example <https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/step_example.py>`__
Bots using this API
-------------------
- `SiteAlert bot <https://telegram.me/SiteAlert_bot>`__
(`source <https://github.com/ilteoood/SiteAlert-Python>`__) by
*ilteoood* - Monitors websites and sends a notification on changes
- `TelegramLoggingBot <https://github.com/aRandomStranger/TelegramLoggingBot>`__
by *aRandomStranger*
- `Telegram
LMGTFY\_bot <https://github.com/GabrielRF/telegram-lmgtfy_bot>`__ by
*GabrielRF*
- `Telegram
UrlProBot <https://github.com/GabrielRF/telegram-urlprobot>`__ by
*GabrielRF*
- `Telegram Proxy
Bot <https://bitbucket.org/master_groosha/telegram-proxy-bot>`__ by
*Groosha* - A simple BITM (bot-in-the-middle) for Telegram acting as
some kind of "proxy".
- `Telegram Proxy Bot <https://github.com/mrgigabyte/proxybot>`__ by
*mrgigabyte* -
``Credits for the original version of this bot goes to`` **Groosha**
``, simply added certain features which I thought were needed``.
- `RadRetroRobot <https://github.com/Tronikart/RadRetroRobot>`__ by
*Tronikart* - Multifunctional Telegram Bot RadRetroRobot.
- `League of Legends bot <https://telegram.me/League_of_Legends_bot>`__
(`source <https://github.com/i32ropie/lol>`__) by *i32ropie*
- `NeoBot <https://github.com/neoranger/NeoBot>`__ by *neoranger*
- `TagAlertBot <https://github.com/pitasi/TagAlertBot>`__ by *pitasi*
Want to have your bot listed here? Send a Telegram message to @eternnoir
or @pevdh.
.. |Download Month| image:: https://img.shields.io/pypi/v/pyTelegramBotAPI.svg
:target: https://pypi.python.org/pypi/pyTelegramBotAPI
.. |Build Status| image:: https://travis-ci.org/eternnoir/pyTelegramBotAPI.svg?branch=master
:target: https://travis-ci.org/eternnoir/pyTelegramBotAPI
.. |Download Month| image:: https://img.shields.io/pypi/dm/pyTelegramBotAPI.svg
:target: https://pypi.python.org/pypi/pyTelegramBotAPI

70
examples/deep_linking.py Normal file
View File

@ -0,0 +1,70 @@
# 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.
#
# In this example we are connecting a user account on a website with a Telegram bot.
# Implementing this will enable you to push notifications (and other content) to your users' Telegram account.
# In this explanation the word 'database' can refer to any form of key-value storage.
# The deep linking explained:
#
# 1. Let the user log in on an actual website with actual username-password authentication.
#
# 2. Generate a unique hashcode (we will call it unique_code)
#
# 3. Save unique_code->username to the database.
#
# 4. Show the user the URL https://telegram.me/YOURBOTNAME?start=unique_code
#
# 5. Now as soon as the user opens this URL in Telegram and presses 'Start',
# your bot will receive a text message containing '/start unique_code',
# where unique_code is of course replaced by the actual hashcode.
#
# 6. Let the bot retrieve the username by querying the database for unique_code.
#
# 7. Save chat_id->username to the database.
#
# 8. Now when your bot receives another message, it can query message.chat.id in the database
# to check if the message is from this specific user. (And handle accordingly) or
# you can push messages to the user using his chat id.
#
# Steps 1 to 4 will have to be implemented in a web server, using a language such as PHP, Python, C# or Java. These
# 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
username = get_username_from_storage(unique_code)
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:
reply = "I have no clue who you are..."
else:
reply = "Please visit me via a provided URL from the website."
bot.reply_to(message, reply)
bot.polling()

View File

@ -0,0 +1,131 @@
"""
This is a detailed example using almost every command of the API
"""
import telebot
from telebot import types
import time
TOKEN = '<token_string>'
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'
}
imageSelect = types.ReplyKeyboardMarkup(one_time_keyboard=True) # create the image selection keyboard
imageSelect.add('cock', 'pussy')
hideBoard = types.ReplyKeyboardRemove() # if sent as reply_markup, will hide the keyboard
# error handling if user isn't known yet
# (obsolete once known users are saved to file, because all users
# had to use the /start command and are therefore known to the bot)
def get_user_step(uid):
if uid in userStep:
return userStep[uid]
else:
knownUsers.append(uid)
userStep[uid] = 0
print "New user detected, who hasn't used \"/start\" yet"
return 0
# only used for console output now
def listener(messages):
"""
When new messages arrive TeleBot will call this function.
"""
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
bot = telebot.TeleBot(TOKEN)
bot.set_update_listener(listener) # register listener
# handle the "/start" command
@bot.message_handler(commands=['start'])
def command_start(m):
cid = m.chat.id
if cid not in knownUsers: # if user hasn't used the "/start" command yet:
knownUsers.append(cid) # save user id, so you could brodcast messages to all users of this bot later
userStep[cid] = 0 # save user id and his current "command level", so he can use the "/getImage" command
bot.send_message(cid, "Hello, stranger, let me scan you...")
bot.send_message(cid, "Scanning complete, I know you now")
command_help(m) # show the new user the help page
else:
bot.send_message(cid, "I already know you, no need for me to scan you again!")
# help page
@bot.message_handler(commands=['help'])
def command_help(m):
cid = m.chat.id
help_text = "The following commands are available: \n"
for key in commands: # generate help text out of the commands dictionary defined at the top
help_text += "/" + key + ": "
help_text += commands[key] + "\n"
bot.send_message(cid, help_text) # send the generated help page
# chat_action example (not a good one...)
@bot.message_handler(commands=['sendLongText'])
def command_long_text(m):
cid = m.chat.id
bot.send_message(cid, "If you think so...")
bot.send_chat_action(cid, 'typing') # show the bot "typing" (max. 5 secs)
time.sleep(3)
bot.send_message(cid, ".")
# user can chose an image (multi-stage command example)
@bot.message_handler(commands=['getImage'])
def command_image(m):
cid = m.chat.id
bot.send_message(cid, "Please choose your image now", reply_markup=imageSelect) # show the keyboard
userStep[cid] = 1 # set the user to the next step (expecting a reply in the listener now)
# if the user has issued the "/getImage" command, process the answer
@bot.message_handler(func=lambda message: get_user_step(message.chat.id) == 1)
def msg_image_select(m):
cid = m.chat.id
text = m.text
# 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
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":
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 try again")
# filter on a specific message
@bot.message_handler(func=lambda message: message.text == "hi")
def command_text_hi(m):
bot.send_message(m.chat.id, "I love you too!")
# default handler for every other text
@bot.message_handler(func=lambda message: True, content_types=['text'])
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()

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -0,0 +1,15 @@
import telebot
TOKEN = 'YOUR BOT TOKEN'
CHAT_ID = 'YOUR CHAT ID'
bot = telebot.TeleBot(TOKEN)
ret_msg = bot.send_voice(CHAT_ID, open('tests/test_data/record.ogg', 'rb'))
file_info = bot.get_file(ret_msg.voice.file_id)
downloaded_file = bot.download_file(file_info.file_path)
with open('new_file.ogg', 'wb') as new_file:
new_file.write(downloaded_file)

View File

@ -7,9 +7,8 @@ API_TOKEN = '<api_token>'
bot = telebot.TeleBot(API_TOKEN)
# Handle '/start' and '/help'
@bot.message_handler(commands=['help, start'])
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
bot.reply_to(message, """\
Hi there, I am EchoBot.
@ -23,6 +22,3 @@ def echo_message(message):
bot.reply_to(message, message.text)
bot.polling()
while True:
pass

View File

@ -0,0 +1,73 @@
# This example show how to write an inline mode telegramt bot use pyTelegramBotAPI.
import telebot
import time
import sys
import logging
from telebot import types
API_TOKEN = '<TOKEN>'
bot = telebot.TeleBot(API_TOKEN)
telebot.logger.setLevel(logging.DEBUG)
@bot.inline_handler(lambda query: query.query == 'text')
def query_text(inline_query):
try:
r = types.InlineQueryResultArticle('1', 'Result1', types.InputTextMessageContent('hi'))
r2 = types.InlineQueryResultArticle('2', 'Result2', types.InputTextMessageContent('hi'))
bot.answer_inline_query(inline_query.id, [r, r2])
except Exception as e:
print(e)
@bot.inline_handler(lambda query: query.query == 'photo1')
def query_photo(inline_query):
try:
r = types.InlineQueryResultPhoto('1',
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/kitten.jpg',
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/kitten.jpg',
input_message_content=types.InputTextMessageContent('hi'))
r2 = types.InlineQueryResultPhoto('2',
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/rooster.jpg',
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/rooster.jpg')
bot.answer_inline_query(inline_query.id, [r, r2], cache_time=1)
except Exception as e:
print(e)
@bot.inline_handler(lambda query: query.query == 'video')
def query_video(inline_query):
try:
r = types.InlineQueryResultVideo('1',
'https://github.com/eternnoir/pyTelegramBotAPI/blob/master/tests/test_data/test_video.mp4?raw=true',
'video/mp4', 'Video',
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/rooster.jpg',
'Title'
)
bot.answer_inline_query(inline_query.id, [r])
except Exception as e:
print(e)
@bot.inline_handler(lambda query: len(query.query) is 0)
def default_query(inline_query):
try:
r = types.InlineQueryResultArticle('1', 'default', types.InputTextMessageContent('default'))
bot.answer_inline_query(inline_query.id, [r])
except Exception as e:
print(e)
def main_loop():
bot.polling(True)
while 1:
time.sleep(3)
if __name__ == '__main__':
try:
main_loop()
except KeyboardInterrupt:
print >> sys.stderr, '\nExiting by user request.\n'
sys.exit(0)

View File

@ -0,0 +1,83 @@
import telebot
from telebot.types import LabeledPrice
from telebot.types import ShippingOption
token = '1234567890:AAAABBBBCCCCDDDDeeeeFFFFgggGHHHH'
provider_token = '1234567890:TEST:AAAABBBBCCCCDDDD' # @BotFather -> Bot Settings -> Payments
bot = telebot.TeleBot(token)
# More about Payments: https://core.telegram.org/bots/payments
prices = [LabeledPrice(label='Working Time Machine', amount=5750), LabeledPrice('Gift wrapping', 500)]
shipping_options = [
ShippingOption(id='instant', title='WorldWide Teleporter').add_price(LabeledPrice('Teleporter', 1000)),
ShippingOption(id='pickup', title='Local pickup').add_price(LabeledPrice('Pickup', 300))]
@bot.message_handler(commands=['start'])
def command_start(message):
bot.send_message(message.chat.id,
"Hello, I'm the demo merchant bot."
" I can sell you a Time Machine."
" Use /buy to order one, /terms for Terms and Conditions")
@bot.message_handler(commands=['terms'])
def command_terms(message):
bot.send_message(message.chat.id,
'Thank you for shopping with our demo bot. We hope you like your new time machine!\n'
'1. If your time machine was not delivered on time, please rethink your concept of time and try again.\n'
'2. If you find that your time machine is not working, kindly contact our future service workshops on Trappist-1e.'
' They will be accessible anywhere between May 2075 and November 4000 C.E.\n'
'3. If you would like a refund, kindly apply for one yesterday and we will have sent it to you immediately.')
@bot.message_handler(commands=['buy'])
def command_pay(message):
bot.send_message(message.chat.id,
"Real cards won't work with me, no money will be debited from your account."
" Use this test card number to pay for your Time Machine: `4242 4242 4242 4242`"
"\n\nThis is your demo invoice:", parse_mode='Markdown')
bot.send_invoice(message.chat.id, title='Working Time Machine',
description='Want to visit your great-great-great-grandparents?'
' Make a fortune at the races?'
' Shake hands with Hammurabi and take a stroll in the Hanging Gardens?'
' Order our Working Time Machine today!',
provider_token=provider_token,
currency='usd',
photo_url='http://erkelzaar.tsudao.com/models/perrotta/TIME_MACHINE.jpg',
photo_height=512, # !=0/None or picture won't be shown
photo_width=512,
photo_size=512,
is_flexible=False, # True If you need to set up Shipping Fee
prices=prices,
start_parameter='time-machine-example',
invoice_payload='HAPPY FRIDAYS COUPON')
@bot.shipping_query_handler(func=lambda query: True)
def shipping(shipping_query):
print(shipping_query)
bot.answer_shipping_query(shipping_query.id, ok=True, shipping_options=shipping_options,
error_message='Oh, seems like our Dog couriers are having a lunch right now. Try again later!')
@bot.pre_checkout_query_handler(func=lambda query: True)
def checkout(pre_checkout_query):
bot.answer_pre_checkout_query(pre_checkout_query.id, ok=True,
error_message="Aliens tried to steal your card's CVV, but we successfully protected your credentials,"
" try to pay again in a few minutes, we need a small rest.")
@bot.message_handler(content_types=['successful_payment'])
def got_payment(message):
bot.send_message(message.chat.id,
'Hoooooray! Thanks for payment! We will proceed your order for `{} {}` as fast as possible! '
'Stay in touch.\n\nUse /buy again to get a Time Machine for your friend!'.format(
message.successful_payment.total_amount / 100, message.successful_payment.currency),
parse_mode='Markdown')
bot.skip_pending = True
bot.polling(none_stop=True, interval=0)

78
examples/step_example.py Normal file
View File

@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
"""
This Example will show you how to use register_next_step handler.
"""
import time
import telebot
from telebot import types
API_TOKEN = '<api_token>'
bot = telebot.TeleBot(API_TOKEN)
user_dict = {}
class User:
def __init__(self, name):
self.name = name
self.age = None
self.sex = None
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
msg = bot.reply_to(message, """\
Hi there, I am Example bot.
What's your name?
""")
bot.register_next_step_handler(msg, process_name_step)
def process_name_step(message):
try:
chat_id = message.chat.id
name = message.text
user = User(name)
user_dict[chat_id] = user
msg = bot.reply_to(message, 'How old are you?')
bot.register_next_step_handler(msg, process_age_step)
except Exception as e:
bot.reply_to(message, 'oooops')
def process_age_step(message):
try:
chat_id = message.chat.id
age = message.text
if not age.isdigit():
msg = bot.reply_to(message, 'Age should be a number. How old are you?')
bot.register_next_step_handler(msg, process_age_step)
return
user = user_dict[chat_id]
user.age = age
markup = types.ReplyKeyboardMarkup(one_time_keyboard=True)
markup.add('Male', 'Female')
msg = bot.reply_to(message, 'What is your gender', reply_markup=markup)
bot.register_next_step_handler(msg, process_sex_step)
except Exception as e:
bot.reply_to(message, 'oooops')
def process_sex_step(message):
try:
chat_id = message.chat.id
sex = message.text
user = user_dict[chat_id]
if (sex == u'Male') or (sex == u'Female'):
user.sex = sex
else:
raise Exception()
bot.send_message(chat_id, 'Nice to meet you ' + user.name + '\n Age:' + str(user.age) + '\n Sex:' + user.sex)
except Exception as e:
bot.reply_to(message, 'oooops')
bot.polling()

View File

@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
# This bot was made specifically for the pyTelegramAPI Telegram chat,
# and goes by the name 'TeleBot (@pyTeleBot)'. Join our group to talk to him!
# WARNING: Tested with Python 2.7
import telebot
import os
text_messages = {
'welcome':
u'Please welcome {name}!\n\n'
u'This chat is intended for questions about and discussion of the pyTelegramBotAPI.\n'
u'To enable group members to answer your questions fast and accurately, please make sure to study the '
u'project\'s documentation (https://github.com/eternnoir/pyTelegramBotAPI/blob/master/README.md) and the '
u'examples (https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples) first.\n\n'
u'I hope you enjoy your stay here!',
'info':
u'My name is TeleBot,\n'
u'I am a bot that assists these wonderful bot-creating people of this bot library group chat.\n'
u'Also, I am still under development. Please improve my functionality by making a pull request! '
u'Suggestions are also welcome, just drop them in this group chat!',
'wrong_chat':
u'Hi there!\nThanks for trying me out. However, this bot can only be used in the pyTelegramAPI group chat.\n'
u'Join us!\n\n'
u'https://telegram.me/joinchat/067e22c60035523fda8f6025ee87e30b'
}
if "TELEBOT_BOT_TOKEN" not in os.environ or "GROUP_CHAT_ID" not in os.environ:
raise AssertionError("Please configure TELEBOT_BOT_TOKEN and GROUP_CHAT_ID as environment variables")
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
@bot.message_handler(func=lambda m: True, content_types=['new_chat_participant'])
def on_user_joins(message):
if not is_api_group(message.chat.id):
return
name = message.new_chat_participant.first_name
if hasattr(message.new_chat_participant, 'last_name') and message.new_chat_participant.last_name is not None:
name += u" {}".format(message.new_chat_participant.last_name)
if hasattr(message.new_chat_participant, 'username') and message.new_chat_participant.username is not None:
name += u" (@{})".format(message.new_chat_participant.username)
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):
bot.reply_to(message, text_messages['wrong_chat'])
return
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)
bot.set_update_listener(listener)
bot.polling()

View File

@ -0,0 +1,45 @@
# Webhook examples using pyTelegramBotAPI
There are 4 examples in this directory using different libraries:
* **Python (CPython):** *webhook_cpython_echo_bot.py*
* **Pros:**
* Official python libraries, it works out of the box (doesn't require to
install anything).
* Works with Python 2 and Python 3 (need to be converted with 2to3).
* **Cons:**
* Ugly code.
* Many things to handle yourself, this can lead to errors.
* Not powerful, do the trick but the performance is low.
* **CherryPy (3.8.0):** *webhook_cherrypy_echo_bot.py*
* **Pros:**
* It's a web application framework, cleaner code, uses objects for defining
the web application.
* Very good performance.
* The project seems to be active, latest version is recent.
* Works with Python 2 and Python 3.
* **Cons:**
* Some things are not very intuitive, reading the doc is a must.
* **Flask (0.10.1):** *webhook_flask_echo_bot.py*
* **Pros:**
* It's a web application framework, cleaner code, uses decorator which can
be nice.
* Good performance.
* It's intuitive if you know how web application works.
* **Cons:**
* The project seems not to be very active, latest version dates 2013.
* They don't recommend to use it with Python 3, but may work.
* May be a oversized for just handling webhook petitions.
* **aiohttp (1.2.0):** *webhook_aiohttp_echo_bot.py*
* **Pros:**
* It's a web application framework
* Python 3 compatible
* Asynchronous, excellent perfomance
* Utilizes new async/await syntax
* **Cons:**
* Requires Python 3.4.2+, don't work with Python 2
*Latest update of this document: 2017-01-30*

View File

@ -0,0 +1,88 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This is a simple echo bot using decorators and webhook with aiohttp
# It echoes any incoming text messages and does not use the polling method.
import logging
import ssl
from aiohttp import web
import telebot
API_TOKEN = '<api_token>'
WEBHOOK_HOST = '<ip/host where the bot is running>'
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
# Quick'n'dirty SSL certificate generation:
#
# openssl genrsa -out webhook_pkey.pem 2048
# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
#
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
# with the same value in you put in WEBHOOK_HOST
WEBHOOK_URL_BASE = "https://{}:{}".format(WEBHOOK_HOST, WEBHOOK_PORT)
WEBHOOK_URL_PATH = "/{}/".format(API_TOKEN)
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
bot = telebot.TeleBot(API_TOKEN)
app = web.Application()
# Process webhook calls
async def handle(request):
if request.match_info.get('token') == bot.token:
request_body_dict = await request.json()
update = telebot.types.Update.de_json(request_body_dict)
bot.process_new_updates([update])
return web.Response()
else:
return web.Response(status=403)
app.router.add_post('/{token}/', handle)
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
bot.reply_to(message,
("Hi there, I am EchoBot.\n"
"I am here to echo your kind words back to you."))
# Handle all other messages
@bot.message_handler(func=lambda message: True, content_types=['text'])
def echo_message(message):
bot.reply_to(message, message.text)
# Remove webhook, it fails sometimes the set if there is a previous webhook
bot.remove_webhook()
# Set webhook
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
certificate=open(WEBHOOK_SSL_CERT, 'r'))
# Build ssl context
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.load_cert_chain(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV)
# Start aiohttp server
web.run_app(
app,
host=WEBHOOK_LISTEN,
port=WEBHOOK_PORT,
ssl_context=context,
)

View File

@ -0,0 +1,90 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 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
API_TOKEN = '<api_token>'
WEBHOOK_HOST = '<ip/host where the bot is running>'
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
# Quick'n'dirty SSL certificate generation:
#
# openssl genrsa -out webhook_pkey.pem 2048
# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
#
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
# with the same value in you put in WEBHOOK_HOST
WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT)
WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN)
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
bot = telebot.TeleBot(API_TOKEN)
# WebhookServer, process webhook calls
class WebhookServer(object):
@cherrypy.expose
def index(self):
if 'content-length' in cherrypy.request.headers and \
'content-type' in cherrypy.request.headers and \
cherrypy.request.headers['content-type'] == 'application/json':
length = int(cherrypy.request.headers['content-length'])
json_string = cherrypy.request.body.read(length).decode("utf-8")
update = telebot.types.Update.de_json(json_string)
bot.process_new_updates([update])
return ''
else:
raise cherrypy.HTTPError(403)
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
bot.reply_to(message,
("Hi there, I am EchoBot.\n"
"I am here to echo your kind words back to you."))
# Handle all other messages
@bot.message_handler(func=lambda message: True, content_types=['text'])
def echo_message(message):
bot.reply_to(message, message.text)
# Remove webhook, it fails sometimes the set if there is a previous webhook
bot.remove_webhook()
# Set webhook
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
certificate=open(WEBHOOK_SSL_CERT, 'r'))
# Disable CherryPy requests log
access_log = cherrypy.log.access_log
for handler in tuple(access_log.handlers):
access_log.removeHandler(handler)
# Start cherrypy server
cherrypy.config.update({
'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
})
cherrypy.quickstart(WebhookServer(), WEBHOOK_URL_PATH, {'/': {}})

View File

@ -0,0 +1,99 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 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
API_TOKEN = '<api_token>'
WEBHOOK_HOST = '<ip/host where the bot is running>'
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
# Quick'n'dirty SSL certificate generation:
#
# openssl genrsa -out webhook_pkey.pem 2048
# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
#
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
# with the same value in you put in WEBHOOK_HOST
WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT)
WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN)
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
bot = telebot.TeleBot(API_TOKEN)
# WebhookHandler, process webhook calls
class WebhookHandler(BaseHTTPServer.BaseHTTPRequestHandler):
server_version = "WebhookHandler/1.0"
def do_HEAD(self):
self.send_response(200)
self.end_headers()
def do_GET(self):
self.send_response(200)
self.end_headers()
def do_POST(self):
if self.path == WEBHOOK_URL_PATH and \
'content-type' in self.headers and \
'content-length' in self.headers and \
self.headers['content-type'] == 'application/json':
json_string = self.rfile.read(int(self.headers['content-length']))
self.send_response(200)
self.end_headers()
update = telebot.types.Update.de_json(json_string)
bot.process_new_messages([update.message])
else:
self.send_error(403)
self.end_headers()
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
bot.reply_to(message,
("Hi there, I am EchoBot.\n"
"I am here to echo your kind words back to you."))
# Handle all other messages
@bot.message_handler(func=lambda message: True, content_types=['text'])
def echo_message(message):
bot.reply_to(message, message.text)
# Remove webhook, it fails sometimes the set if there is a previous webhook
bot.remove_webhook()
# Set webhook
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.socket = ssl.wrap_socket(httpd.socket,
certfile=WEBHOOK_SSL_CERT,
keyfile=WEBHOOK_SSL_PRIV,
server_side=True)
httpd.serve_forever()

View File

@ -0,0 +1,84 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 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
API_TOKEN = '<api_token>'
WEBHOOK_HOST = '<ip/host where the bot is running>'
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
# Quick'n'dirty SSL certificate generation:
#
# openssl genrsa -out webhook_pkey.pem 2048
# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
#
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
# with the same value in you put in WEBHOOK_HOST
WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT)
WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN)
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
bot = telebot.TeleBot(API_TOKEN)
app = flask.Flask(__name__)
# Empty webserver index, return nothing, just http 200
@app.route('/', methods=['GET', 'HEAD'])
def index():
return ''
# Process webhook calls
@app.route(WEBHOOK_URL_PATH, methods=['POST'])
def webhook():
if flask.request.headers.get('content-type') == 'application/json':
json_string = flask.request.get_data().decode('utf-8')
update = telebot.types.Update.de_json(json_string)
bot.process_new_updates([update])
return ''
else:
flask.abort(403)
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
bot.reply_to(message,
("Hi there, I am EchoBot.\n"
"I am here to echo your kind words back to you."))
# Handle all other messages
@bot.message_handler(func=lambda message: True, content_types=['text'])
def echo_message(message):
bot.reply_to(message, message.text)
# Remove webhook, it fails sometimes the set if there is a previous webhook
bot.remove_webhook()
# Set webhook
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
certificate=open(WEBHOOK_SSL_CERT, 'r'))
# Start flask server
app.run(host=WEBHOOK_LISTEN,
port=WEBHOOK_PORT,
ssl_context=(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV),
debug=True)

View File

@ -0,0 +1,29 @@
import telebot
import os
from flask import Flask, request
bot = telebot.TeleBot('<api_token>')
server = Flask(__name__)
@bot.message_handler(commands=['start'])
def start(message):
bot.reply_to(message, 'Hello, ' + message.from_user.first_name)
@bot.message_handler(func=lambda message: True, content_types=['text'])
def echo_message(message):
bot.reply_to(message, message.text)
@server.route("/bot", methods=['POST'])
def getMessage():
bot.process_new_updates([telebot.types.Update.de_json(request.stream.read().decode("utf-8"))])
return "!", 200
@server.route("/")
def webhook():
bot.remove_webhook()
bot.set_webhook(url="https://herokuProject_url/bot")
return "!", 200
server.run(host="0.0.0.0", port=os.environ.get('PORT', 5000))
server = Flask(__name__)

View File

@ -0,0 +1,94 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 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
API_TOKEN = '<api_token>'
WEBHOOK_CERT = "./cert.pem"
WEBHOOK_PKEY = "./pkey.pem"
WEBHOOK_HOST = "<domain_or_ip>"
WEBHOOK_SECRET = "<secret_uri_for_updates"
WEBHOOK_PORT = 88
WEBHOOK_URL_BASE = "https://{0}:{1}/{2}".format(WEBHOOK_HOST, str(WEBHOOK_PORT), WEBHOOK_SECRET)
# Quick'n'dirty SSL certificate generation:
#
# openssl genrsa -out pkey.pem 2048
# openssl req -new -x509 -days 3650 -key pkey.pem -out cert.pem
#
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
# with the same value in you put in WEBHOOK_HOST
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 \
self.request.headers['Content-Type'] == "application/json":
# length = int(self.request.headers['Content-Length'])
json_data = self.request.body.decode("utf-8")
update = telebot.types.Update.de_json(json_data)
bot.process_new_updates([update])
self.write("")
self.finish()
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):
bot.reply_to(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'))
tornado.options.options.logging = None
tornado.options.parse_command_line()
signal.signal(signal.SIGINT, signal_handler)
application = tornado.web.Application([
(r"/", Root),
(r"/" + WEBHOOK_SECRET, webhook_serv)
])
http_server = tornado.httpserver.HTTPServer(application, ssl_options={
"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()

View File

@ -1,4 +1,5 @@
py==1.4.29
pytest==2.7.2
pytest==3.0.2
requests==2.7.0
six==1.9.0
wheel==0.24.0

View File

@ -1,18 +1,27 @@
#!/usr/bin/env python
from setuptools import setup
from io import open
def readme():
with open('README.rst', encoding='utf-8') as f:
return f.read()
setup(name='pyTelegramBotAPI',
version='0.2.0',
version='3.1.1',
description='Python Telegram bot api. ',
long_description=readme(),
author='eternnoir',
author_email='eternnoir@gmail.com',
url='https://github.com/eternnoir/pyTelegramBotAPI',
packages=['telebot'],
license='GPL2',
keywords='tools',
install_requires=['pytest', 'requests'],
keywords='telegram bot api tools',
install_requires=['requests', 'six'],
extras_require={
'json': 'ujson',
},
classifiers=[
'Development Status :: 4 - Beta',
'Development Status :: 5 - Production/Stable',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,37 @@
# -*- coding: utf-8 -*-
try:
import ujson as json
except ImportError:
import json
import requests
try:
from requests.packages.urllib3 import fields
format_header_param = fields.format_header_param
except ImportError:
format_header_param = None
import telebot
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}"
CONNECT_TIMEOUT = 3.5
READ_TIMEOUT = 9999
def _make_request(token, method_name, method='get', params=None, files=None):
def _get_req_session():
return util.per_thread('req_session', lambda: requests.session())
def _make_request(token, method_name, method='get', params=None, files=None, base_url=API_URL):
"""
Makes a request to the Telegram API.
:param token: The bot's API token. (Created with @BotFather)
@ -14,27 +39,77 @@ def _make_request(token, method_name, method='get', params=None, files=None):
:param method: HTTP method to be used. Defaults to 'get'.
:param params: Optional parameters. Should be a dictionary with key-value pairs.
:param files: Optional files.
:return:
:return: The result parsed to a JSON dictionary.
"""
request_url = base_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)
logger.debug("The server returned: '{0}'".format(result.text.encode('utf8')))
return _check_result(method_name, result)['result']
def _check_result(method_name, result):
"""
Checks whether `result` is a valid API response.
A result is considered invalid if:
- The server returned an HTTP response code other than 200
- The content of the result is invalid JSON.
- The method call was unsuccessful (The JSON 'ok' field equals False)
:raises ApiException: if one of the above listed cases is applicable
:param method_name: The name of the method called
:param result: The returned result of the method request
:return: The result parsed to a JSON dictionary.
"""
request_url = telebot.API_URL + 'bot' + token + '/' + method_name
result = requests.request(method, request_url, params=params, files=files)
if result.status_code != 200:
raise ApiException(method_name, result)
msg = 'The server returned HTTP {0} {1}. Response body:\n[{2}]' \
.format(result.status_code, result.reason, result.text.encode('utf8'))
raise ApiException(msg, method_name, result)
try:
result_json = result.json()
if not result_json['ok']:
raise Exception()
except:
raise ApiException(method_name, result)
return result_json['result']
msg = 'The server returned an invalid JSON response. Response body:\n[{0}]' \
.format(result.text.encode('utf8'))
raise ApiException(msg, method_name, result)
if not result_json['ok']:
msg = 'Error code: {0} Description: {1}' \
.format(result_json['error_code'], result_json['description'])
raise ApiException(msg, method_name, result)
return result_json
def get_me(token):
method_url = 'getMe'
method_url = r'getMe'
return _make_request(token, method_url)
def send_message(token, chat_id, text, disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None):
def get_file(token, file_id):
method_url = r'getFile'
return _make_request(token, method_url, params={'file_id': file_id})
def download_file(token, file_path):
url = FILE_URL.format(token, file_path)
result = _get_req_session().get(url)
if result.status_code != 200:
msg = 'The server returned HTTP {0} {1}. Response body:\n[{2}]' \
.format(result.status_code, result.reason, result.text)
raise ApiException(msg, 'Download file', result)
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):
"""
Use this method to send text messages. On success, the sent Message is returned.
:param token:
@ -53,10 +128,40 @@ def send_message(token, chat_id, text, disable_web_page_preview=None, reply_to_m
payload['reply_to_message_id'] = reply_to_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
if parse_mode:
payload['parse_mode'] = parse_mode
if disable_notification:
payload['disable_notification'] = disable_notification
return _make_request(token, method_url, params=payload, method='post')
def set_webhook(token, url=None, certificate=None, max_connections=None, allowed_updates=None):
method_url = r'setWebhook'
payload = {
'url': url if url else "",
}
files = None
if certificate:
files = {'certificate': certificate}
if max_connections:
payload['max_connections'] = max_connections
if allowed_updates:
payload['allowed_updates'] = json.dumps(allowed_updates)
return _make_request(token, method_url, params=payload, files=files)
def delete_webhook(token):
method_url = r'deleteWebhook'
return _make_request(token, method_url)
def get_webhook_info(token):
method_url = r'getWebhookInfo'
payload = {}
return _make_request(token, method_url, params=payload)
def get_updates(token, offset=None, limit=None, timeout=None):
def get_updates(token, offset=None, limit=None, timeout=None, allowed_updates=None):
method_url = r'getUpdates'
payload = {}
if offset:
@ -65,6 +170,8 @@ def get_updates(token, offset=None, limit=None, timeout=None):
payload['limit'] = limit
if timeout:
payload['timeout'] = timeout
if allowed_updates:
payload['allowed_updates'] = json.dumps(allowed_updates)
return _make_request(token, method_url, params=payload)
@ -78,28 +185,100 @@ def get_user_profile_photos(token, user_id, offset=None, limit=None):
return _make_request(token, method_url, params=payload)
def forward_message(token, chat_id, from_chat_id, message_id):
method_url = r'forwardMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
def get_chat(token, chat_id):
method_url = r'getChat'
payload = {'chat_id': chat_id}
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):
def leave_chat(token, chat_id):
method_url = r'leaveChat'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload)
def get_chat_administrators(token, chat_id):
method_url = r'getChatAdministrators'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload)
def get_chat_members_count(token, chat_id):
method_url = r'getChatMembersCount'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload)
def get_chat_member(token, chat_id, user_id):
method_url = r'getChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
return _make_request(token, method_url, params=payload)
def forward_message(token, chat_id, from_chat_id, message_id, disable_notification=None):
method_url = r'forwardMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if disable_notification:
payload['disable_notification'] = disable_notification
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,
disable_notification=None):
method_url = r'sendPhoto'
payload = {'chat_id': chat_id}
files = {'photo': photo}
files = None
if not util.is_string(photo):
files = {'photo': photo}
else:
payload['photo'] = photo
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 disable_notification:
payload['disable_notification'] = disable_notification
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_location(token, chat_id, latitude, longitude, reply_to_message_id=None, reply_markup=None):
def send_location(token, chat_id, latitude, longitude, reply_to_message_id=None, reply_markup=None,
disable_notification=None):
method_url = r'sendLocation'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
if reply_to_message_id:
payload['reply_to_message_id'] = reply_to_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
if disable_notification:
payload['disable_notification'] = disable_notification
return _make_request(token, method_url, params=payload)
def send_venue(token, chat_id, latitude, longitude, title, address, foursquare_id=None, disable_notification=None,
reply_to_message_id=None, reply_markup=None):
method_url = r'sendVenue'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address}
if foursquare_id:
payload['foursquare_id'] = foursquare_id
if disable_notification:
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)
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):
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:
payload['disable_notification'] = disable_notification
if reply_to_message_id:
payload['reply_to_message_id'] = reply_to_message_id
if reply_markup:
@ -113,26 +292,565 @@ def send_chat_action(token, chat_id, action):
return _make_request(token, method_url, params=payload)
def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None):
method_url = get_method_by_type(data_type)
def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None, timeout=None):
method_url = r'sendVideo'
payload = {'chat_id': chat_id}
files = {data_type: data}
files = None
if not util.is_string(data):
files = {'video': data}
else:
payload['video'] = 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 disable_notification:
payload['disable_notification'] = disable_notification
if timeout:
payload['connect-timeout'] = timeout
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None, timeout=None):
method_url = r'sendVoice'
payload = {'chat_id': chat_id}
files = None
if not util.is_string(voice):
files = {'voice': voice}
else:
payload['voice'] = voice
if caption:
payload['caption'] = caption
if duration:
payload['duration'] = duration
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 disable_notification:
payload['disable_notification'] = disable_notification
if timeout:
payload['connect-timeout'] = timeout
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None, timeout=None):
method_url = r'sendVideoNote'
payload = {'chat_id': chat_id}
files = None
if not util.is_string(data):
files = {'video_note': data}
else:
payload['video_note'] = data
if duration:
payload['duration'] = duration
if length:
payload['length'] = length
else:
payload['length'] = 639 # seems like it is MAX length size
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 disable_notification:
payload['disable_notification'] = disable_notification
if timeout:
payload['connect-timeout'] = timeout
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None, reply_to_message_id=None,
reply_markup=None, disable_notification=None, timeout=None):
method_url = r'sendAudio'
payload = {'chat_id': chat_id}
files = None
if not util.is_string(audio):
files = {'audio': audio}
else:
payload['audio'] = audio
if caption:
payload['caption'] = caption
if duration:
payload['duration'] = duration
if performer:
payload['performer'] = performer
if title:
payload['title'] = title
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 disable_notification:
payload['disable_notification'] = disable_notification
if timeout:
payload['connect-timeout'] = timeout
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None, disable_notification=None,
timeout=None, caption=None):
method_url = get_method_by_type(data_type)
payload = {'chat_id': chat_id}
files = None
if not util.is_string(data):
files = {data_type: data}
else:
payload[data_type] = data
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 disable_notification:
payload['disable_notification'] = disable_notification
if timeout:
payload['connect-timeout'] = timeout
if caption:
payload['caption'] = caption
return _make_request(token, method_url, params=payload, files=files, method='post')
def get_method_by_type(data_type):
if data_type == 'audio':
return 'sendAudio'
if data_type == 'document':
return 'sendDocument'
return r'sendDocument'
if data_type == 'sticker':
return 'sendSticker'
if data_type == 'video':
return 'sendVideo'
return r'sendSticker'
def kick_chat_member(token, chat_id, user_id, until_date=None):
method_url = 'kickChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
if until_date:
payload['until_date'] = until_date
return _make_request(token, method_url, params=payload, method='post')
def unban_chat_member(token, chat_id, user_id):
method_url = 'unbanChatMember'
payload = {'chat_id': chat_id, 'user_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):
method_url = 'restrictChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
if until_date:
payload['until_date'] = until_date
if can_send_messages:
payload['can_send_messages'] = can_send_messages
if can_send_media_messages:
payload['can_send_media_messages'] = can_send_media_messages
if can_send_other_messages:
payload['can_send_other_messages'] = can_send_other_messages
if can_add_web_page_previews:
payload['can_add_web_page_previews'] = can_add_web_page_previews
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):
method_url = 'promoteChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
if can_change_info:
payload['can_change_info'] = can_change_info
if can_post_messages:
payload['can_post_messages'] = can_post_messages
if can_edit_messages:
payload['can_edit_messages'] = can_edit_messages
if can_delete_messages:
payload['can_delete_messages'] = can_delete_messages
if can_invite_users:
payload['can_invite_users'] = can_invite_users
if can_restrict_members:
payload['can_restrict_members'] = can_restrict_members
if can_pin_messages:
payload['can_pin_messages'] = can_pin_messages
if can_promote_members:
payload['can_promote_members'] = can_promote_members
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}
return _make_request(token, method_url, params=payload, method='post')
def set_chat_photo(token, chat_id, photo):
method_url = 'setChatPhoto'
payload = {'chat_id': chat_id}
files = None
if not util.is_string(photo):
files = {'photo': photo}
else:
payload['photo'] = photo
return _make_request(token, method_url, params=payload, files=files, method='post')
def delete_chat_photo(token, chat_id):
method_url = 'deleteChatPhoto'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload, method='post')
def set_chat_title(token, chat_id, title):
method_url = 'setChatTitle'
payload = {'chat_id': chat_id, 'title': title}
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):
method_url = 'pinChatMessage'
payload = {'chat_id': chat_id, 'message_id': message_id, 'disable_notification': disable_notification}
return _make_request(token, method_url, params=payload, method='post')
def unpin_chat_message(token, chat_id):
method_url = 'unpinChatMessage'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload, method='post')
# Updating messages
def edit_message_text(token, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None,
disable_web_page_preview=None, reply_markup=None):
method_url = r'editMessageText'
payload = {'text': text}
if chat_id:
payload['chat_id'] = chat_id
if message_id:
payload['message_id'] = message_id
if inline_message_id:
payload['inline_message_id'] = inline_message_id
if parse_mode:
payload['parse_mode'] = parse_mode
if disable_web_page_preview:
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)
def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
method_url = r'editMessageCaption'
payload = {'caption': caption}
if chat_id:
payload['chat_id'] = chat_id
if message_id:
payload['message_id'] = message_id
if inline_message_id:
payload['inline_message_id'] = inline_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload)
def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
method_url = r'editMessageReplyMarkup'
payload = {}
if chat_id:
payload['chat_id'] = chat_id
if message_id:
payload['message_id'] = message_id
if inline_message_id:
payload['inline_message_id'] = inline_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload)
def 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)
# Game
def send_game(token, chat_id, game_short_name, disable_notification=None, reply_to_message_id=None, reply_markup=None):
method_url = r'sendGame'
payload = {'chat_id': chat_id, 'game_short_name': game_short_name}
if disable_notification:
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)
return _make_request(token, method_url, params=payload)
# https://core.telegram.org/bots/api#setgamescore
def set_game_score(token, user_id, score, force=None, disable_edit_message=None, chat_id=None, message_id=None,
inline_message_id=None):
"""
Use this method to set the score of the specified user in a game. On success, if the message was sent by the bot, returns the edited Message, otherwise returns True. Returns an error, if the new score is not greater than the user's current score in the chat.
:param token: Bot's token (you don't need to fill this)
:param user_id: User identifier
:param score: New score, must be non-negative
:param force: (Optional) Pass True, if the high score is allowed to decrease. This can be useful when fixing mistakes or banning cheaters
:param disable_edit_message: (Optional) Pass True, if the game message should not be automatically edited to include the current scoreboard
:param chat_id: (Optional, required if inline_message_id is not specified) Unique identifier for the target chat (or username of the target channel in the format @channelusername)
:param message_id: (Optional, required if inline_message_id is not specified) Unique identifier of the sent message
:param inline_message_id: (Optional, required if chat_id and message_id are not specified) Identifier of the inline message
:return:
"""
method_url = r'setGameScore'
payload = {'user_id': user_id, 'score': score}
if force:
payload['force'] = force
if chat_id:
payload['chat_id'] = chat_id
if message_id:
payload['message_id'] = message_id
if inline_message_id:
payload['inline_message_id'] = inline_message_id
if disable_edit_message:
payload['disable_edit_message'] = disable_edit_message
return _make_request(token, method_url, params=payload)
# https://core.telegram.org/bots/api#getgamehighscores
def get_game_high_scores(token, user_id, chat_id=None, message_id=None, inline_message_id=None):
"""
Use this method to get data for high score tables. Will return the score of the specified user and several of his neighbors in a game. On success, returns an Array of GameHighScore objects.
This method will currently return scores for the target user, plus two of his closest neighbors on each side. Will also return the top three users if the user and his neighbors are not among them. Please note that this behavior is subject to change.
:param token: Bot's token (you don't need to fill this)
:param user_id: Target user id
:param chat_id: (Optional, required if inline_message_id is not specified) Unique identifier for the target chat (or username of the target channel in the format @channelusername)
:param message_id: (Optional, required if inline_message_id is not specified) Unique identifier of the sent message
:param inline_message_id: (Optional, required if chat_id and message_id are not specified) Identifier of the inline message
:return:
"""
method_url = r'getGameHighScores'
payload = {'user_id': user_id}
if chat_id:
payload['chat_id'] = chat_id
if message_id:
payload['message_id'] = message_id
if inline_message_id:
payload['inline_message_id'] = inline_message_id
return _make_request(token, method_url, params=payload)
# 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):
"""
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)
:param chat_id: Unique identifier for the target private chat
:param title: Product name
:param description: Product description
:param invoice_payload: Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes.
:param provider_token: Payments provider token, obtained via @Botfather
:param currency: Three-letter ISO 4217 currency code, see https://core.telegram.org/bots/payments#supported-currencies
:param prices: Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.)
:param start_parameter: Unique deep-linking parameter that can be used to generate this invoice when used as a start parameter
:param photo_url: URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service. People like it better when they see what they are paying for.
:param photo_size: Photo size
:param photo_width: Photo width
:param photo_height: Photo height
:param need_name: Pass True, if you require the user's full name to complete the order
:param need_phone_number: Pass True, if you require the user's phone number to complete the order
:param need_email: Pass True, if you require the user's email to complete the order
:param need_shipping_address: Pass True, if you require the user's shipping address to complete the order
:param is_flexible: Pass True, if the final price depends on the shipping method
: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:
"""
method_url = r'sendInvoice'
payload = {'chat_id': chat_id, 'title': title, 'description': description, 'payload': invoice_payload,
'provider_token': provider_token, 'start_parameter': start_parameter, 'currency': currency,
'prices': _convert_list_json_serializable(prices)}
if photo_url:
payload['photo_url'] = photo_url
if photo_size:
payload['photo_size'] = photo_size
if photo_width:
payload['photo_width'] = photo_width
if photo_height:
payload['photo_height'] = photo_height
if need_name:
payload['need_name'] = need_name
if need_phone_number:
payload['need_phone_number'] = need_phone_number
if need_email:
payload['need_email'] = need_email
if need_shipping_address:
payload['need_shipping_address'] = need_shipping_address
if is_flexible:
payload['is_flexible'] = is_flexible
if disable_notification:
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)
return _make_request(token, method_url, params=payload)
def answer_shipping_query(token, shipping_query_id, ok, shipping_options=None, error_message=None):
"""
If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, the Bot API will send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries. On success, True is returned.
:param token: Bot's token (you don't need to fill this)
:param shipping_query_id: Unique identifier for the query to be answered
: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:
"""
method_url = 'answerShippingQuery'
payload = {'shipping_query_id': shipping_query_id, 'ok': ok}
if shipping_options:
payload['reply_markup'] = _convert_list_json_serializable(shipping_options)
if error_message:
payload['error_message'] = error_message
return _make_request(token, method_url, params=payload)
def answer_pre_checkout_query(token, pre_checkout_query_id, ok, error_message=None):
"""
Once the user has confirmed their payment and shipping details, the Bot API sends the final confirmation in the form of an Update with the field pre_checkout_query. Use this method to respond to such pre-checkout queries. On success, True is returned. Note: The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.
:param token: Bot's token (you don't need to fill this)
: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:
"""
method_url = 'answerPreCheckoutQuery'
payload = {'pre_checkout_query_id': pre_checkout_query_id, 'ok': ok}
if error_message:
payload['error_message'] = error_message
return _make_request(token, method_url, params=payload)
# InlineQuery
def answer_callback_query(token, callback_query_id, text=None, show_alert=None, url=None, cache_time=None):
"""
Use this method to send answers to callback queries sent from inline keyboards. The answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, True is returned.
Alternatively, the user can be redirected to the specified Game URL. For this option to work, you must first create a game for your bot via BotFather and accept the terms. Otherwise, you may use links like telegram.me/your_bot?start=XXXX that open your bot with a parameter.
:param token: Bot's token (you don't need to fill this)
:param callback_query_id: Unique identifier for the query to be answered
:param text: (Optional) Text of the notification. If not specified, nothing will be shown to the user, 0-200 characters
:param show_alert: (Optional) If true, an alert will be shown by the client instead of a notification at the top of the chat screen. Defaults to false.
:param url: (Optional) URL that will be opened by the user's client. If you have created a Game and accepted the conditions via @Botfather, specify the URL that opens your game note that this will only work if the query comes from a callback_game button.
Otherwise, you may use links like telegram.me/your_bot?start=XXXX that open your bot with a parameter.
:param cache_time: (Optional) The maximum amount of time in seconds that the result of the callback query may be cached client-side. Telegram apps will support caching starting in version 3.14. Defaults to 0.
:return:
"""
method_url = 'answerCallbackQuery'
payload = {'callback_query_id': callback_query_id}
if text:
payload['text'] = text
if show_alert:
payload['show_alert'] = show_alert
if url:
payload['url'] = url
if cache_time:
payload['cache_time'] = cache_time
return _make_request(token, method_url, params=payload, method='post')
def answer_inline_query(token, inline_query_id, results, cache_time=None, is_personal=None, next_offset=None,
switch_pm_text=None, switch_pm_parameter=None):
method_url = 'answerInlineQuery'
payload = {'inline_query_id': inline_query_id, 'results': _convert_list_json_serializable(results)}
if cache_time:
payload['cache_time'] = cache_time
if is_personal:
payload['is_personal'] = is_personal
if next_offset is not None:
payload['next_offset'] = next_offset
if switch_pm_text:
payload['switch_pm_text'] = switch_pm_text
if switch_pm_parameter:
payload['switch_pm_parameter'] = switch_pm_parameter
return _make_request(token, method_url, params=payload, method='post')
def get_sticker_set(token, name):
method_url = 'getStickerSet'
return _make_request(token, method_url, params={'name': name})
def upload_sticker_file(token, user_id, png_sticker):
method_url = 'uploadStickerFile'
payload = {'user_id': user_id}
files = {'png_sticker': 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):
method_url = 'createNewStickerSet'
payload = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis}
files = None
if not util.is_string(png_sticker):
files = {'png_sticker': png_sticker}
else:
payload['png_sticker'] = png_sticker
if contains_masks:
payload['contains_masks'] = contains_masks
if mask_position:
payload['mask_position'] = mask_position.to_json()
return _make_request(token, method_url, params=payload, files=files, method='post')
def add_sticker_to_set(token, user_id, name, png_sticker, emojis, mask_position):
method_url = 'addStickerToSet'
payload = {'user_id': user_id, 'name': name, 'emojis': emojis}
files = None
if not util.is_string(png_sticker):
files = {'png_sticker': png_sticker}
else:
payload['png_sticker'] = png_sticker
if mask_position:
payload['mask_position'] = mask_position.to_json()
return _make_request(token, method_url, params=payload, files=files, method='post')
def set_sticker_position_in_set(token, sticker, position):
method_url = 'setStickerPositionInSet'
payload = {'sticker': sticker, 'position': position}
return _make_request(token, method_url, params=payload, method='post')
def delete_sticker_from_set(token, sticker):
method_url = 'deleteStickerFromSet'
payload = {'sticker': sticker}
return _make_request(token, method_url, params=payload, method='post')
def _convert_list_json_serializable(results):
ret = ''
for r in results:
if isinstance(r, types.JsonSerializable):
ret = ret + r.to_json() + ','
if len(ret) > 0:
ret = ret[:-1]
return '[' + ret + ']'
def _convert_markup(markup):
@ -141,11 +859,25 @@ def _convert_markup(markup):
return markup
def _no_encode(func):
def wrapper(key, val):
if key == 'filename':
return '{0}={1}'.format(key, val)
else:
return func(key, val)
return wrapper
class ApiException(Exception):
"""
This class represents an Exception thrown when a call to the Telegram API fails.
In addition to an informative message, it has a `function_name` and a `result` attribute, which respectively
contain the name of the failed function and the returned result that made the function to be considered as
failed.
"""
def __init__(self, function_name, result):
super(ApiException, self).__init__('{0} failed. Returned result: {1}'.format(function_name, result))
def __init__(self, msg, function_name, result):
super(ApiException, self).__init__("A request to the Telegram API was unsuccessful. {0}".format(msg))
self.function_name = function_name
self.result = result

File diff suppressed because it is too large Load Diff

256
telebot/util.py Normal file
View File

@ -0,0 +1,256 @@
# -*- coding: utf-8 -*-
import threading
import traceback
import re
import sys
import six
from six import string_types
# Python3 queue support.
try:
import Queue
except ImportError:
import queue as Queue
from telebot import logger
thread_local = threading.local()
class WorkerThread(threading.Thread):
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()
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.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()
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()
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 clear_exceptions(self):
self.exception_event.clear()
self.continue_event.set()
def stop(self):
self._running = False
class ThreadPool:
def __init__(self, num_threads=2):
self.tasks = Queue.Queue()
self.workers = [WorkerThread(self.on_exception, self.tasks) for _ in range(num_threads)]
self.num_threads = num_threads
self.exception_event = threading.Event()
self.exc_info = None
def put(self, func, *args, **kwargs):
self.tasks.put((func, args, kwargs))
def on_exception(self, worker_thread, exc_info):
self.exc_info = exc_info
self.exception_event.set()
worker_thread.continue_event.set()
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()
def close(self):
for worker in self.workers:
worker.stop()
for worker in self.workers:
worker.join()
class AsyncTask:
def __init__(self, target, *args, **kwargs):
self.target = target
self.args = args
self.kwargs = kwargs
self.done = False
self.thread = threading.Thread(target=self._run)
self.thread.start()
def _run(self):
try:
self.result = self.target(*self.args, **self.kwargs)
except:
self.result = sys.exc_info()
self.done = True
def wait(self):
if not self.done:
self.thread.join()
if isinstance(self.result, BaseException):
six.reraise(self.result[0], self.result[1], self.result[2])
else:
return self.result
def async():
def decorator(fn):
def wrapper(*args, **kwargs):
return AsyncTask(fn, *args, **kwargs)
return wrapper
return decorator
def is_string(var):
return isinstance(var, string_types)
def is_command(text):
"""
Checks if `text` is a command. Telegram chat commands start with the '/' character.
:param text: Text to check.
:return: True if `text` is a command, else False.
"""
return text.startswith('/')
def extract_command(text):
"""
Extracts the command from `text` (minus the '/') if `text` is a command (see is_command).
If `text` is not a command, this function returns None.
Examples:
extract_command('/help'): 'help'
extract_command('/help@BotName'): 'help'
extract_command('/search black eyed peas'): 'search'
extract_command('Good day to you'): None
:param text: String to extract the command from
:return: the command if `text` is a command (according to is_command), else None.
"""
return text.split()[0].split('@')[0][1:] if is_command(text) else None
def split_string(text, chars_per_string):
"""
Splits one string into multiple strings, with a maximum amount of `chars_per_string` characters per string.
This is very useful for splitting one giant message into multiples.
:param text: The text to split
:param chars_per_string: The number of characters per line the text is split into.
:return: The splitted text as a list of strings.
"""
return [text[i:i + chars_per_string] for i in range(0, len(text), chars_per_string)]
# CREDITS TO http://stackoverflow.com/questions/12317940#answer-12320352
def or_set(self):
self._set()
self.changed()
def or_clear(self):
self._clear()
self.changed()
def orify(e, changed_callback):
e._set = e.set
e._clear = e.clear
e.changed = changed_callback
e.set = lambda: or_set(e)
e.clear = lambda: or_clear(e)
def OrEvent(*events):
or_event = threading.Event()
def changed():
bools = [e.is_set() for e in events]
if any(bools):
or_event.set()
else:
or_event.clear()
def busy_wait():
while not or_event.is_set():
or_event._wait(3)
for e in events:
orify(e, changed)
or_event._wait = or_event.wait
or_event.wait = busy_wait
changed()
return or_event
def extract_arguments(text):
"""
Returns the argument after the command.
Examples:
extract_arguments("/get name"): 'name'
extract_arguments("/get"): ''
extract_arguments("/get@botName name"): 'name'
: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)
result = regexp.match(text)
return result.group(2) if is_command(text) else None
def per_thread(key, construct_value):
try:
return getattr(thread_local, key)
except AttributeError:
value = construct_value()
setattr(thread_local, key, value)
return value

BIN
tests/test_data/record.mp3 Normal file

Binary file not shown.

BIN
tests/test_data/record.ogg Normal file

Binary file not shown.

BIN
tests/test_data/record.wav Normal file

Binary file not shown.

Binary file not shown.

411
tests/test_telebot.py Normal file
View File

@ -0,0 +1,411 @@
# -*- coding: utf-8 -*-
import sys
sys.path.append('../')
import time
import pytest
import os
import telebot
from telebot import types
from telebot import util
should_skip = 'TOKEN' and 'CHAT_ID' not in os.environ
if not should_skip:
TOKEN = os.environ['TOKEN']
CHAT_ID = os.environ['CHAT_ID']
GROUP_ID = os.environ['GROUP_ID']
@pytest.mark.skipif(should_skip, reason="No environment variables configured")
class TestTeleBot:
def test_message_listener(self):
msg_list = []
for x in range(100):
msg_list.append(self.create_text_message('Message ' + str(x)))
def listener(messages):
assert len(messages) == 100
tb = telebot.TeleBot('')
tb.set_update_listener(listener)
def test_message_handler(self):
tb = telebot.TeleBot('')
msg = self.create_text_message('/help')
@tb.message_handler(commands=['help', 'start'])
def command_handler(message):
message.text = 'got'
tb.process_new_messages([msg])
time.sleep(1)
assert msg.text == 'got'
def test_message_handler_reg(self):
bot = telebot.TeleBot('')
msg = self.create_text_message(r'https://web.telegram.org/')
@bot.message_handler(regexp='((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)')
def command_url(message):
msg.text = 'got'
bot.process_new_messages([msg])
time.sleep(1)
assert msg.text == 'got'
def test_message_handler_lambda(self):
bot = telebot.TeleBot('')
msg = self.create_text_message(r'lambda_text')
@bot.message_handler(func=lambda message: r'lambda' in message.text)
def command_url(message):
msg.text = 'got'
bot.process_new_messages([msg])
time.sleep(1)
assert msg.text == 'got'
def test_message_handler_lambda_fail(self):
bot = telebot.TeleBot('')
msg = self.create_text_message(r'text')
@bot.message_handler(func=lambda message: r'lambda' in message.text)
def command_url(message):
msg.text = 'got'
bot.process_new_messages([msg])
time.sleep(1)
assert not msg.text == 'got'
def test_message_handler_reg_fail(self):
bot = telebot.TeleBot('')
msg = self.create_text_message(r'web.telegram.org/')
@bot.message_handler(regexp='((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)')
def command_url(message):
msg.text = 'got'
bot.process_new_messages([msg])
time.sleep(1)
assert not msg.text == 'got'
def test_send_message_with_markdown(self):
tb = telebot.TeleBot(TOKEN)
markdown = """
*bold text*
_italic text_
[text](URL)
"""
ret_msg = tb.send_message(CHAT_ID, markdown, parse_mode="Markdown")
assert ret_msg.message_id
def test_send_message_with_disable_notification(self):
tb = telebot.TeleBot(TOKEN)
markdown = """
*bold text*
_italic text_
[text](URL)
"""
ret_msg = tb.send_message(CHAT_ID, markdown, parse_mode="Markdown", disable_notification=True)
assert ret_msg.message_id
def test_send_file(self):
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_document(CHAT_ID, file_data)
assert ret_msg.message_id
ret_msg = tb.send_document(CHAT_ID, ret_msg.document.file_id)
assert ret_msg.message_id
def test_send_file_dis_noti(self):
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_document(CHAT_ID, file_data, disable_notification=True)
assert ret_msg.message_id
ret_msg = tb.send_document(CHAT_ID, ret_msg.document.file_id)
assert ret_msg.message_id
def test_send_file_caption(self):
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_document(CHAT_ID, file_data, caption="Test")
assert ret_msg.message_id
ret_msg = tb.send_document(CHAT_ID, ret_msg.document.file_id)
assert ret_msg.message_id
def test_send_video(self):
file_data = open('./test_data/test_video.mp4', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_video(CHAT_ID, file_data)
assert ret_msg.message_id
def test_send_video_dis_noti(self):
file_data = open('./test_data/test_video.mp4', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_video(CHAT_ID, file_data, disable_notification=True)
assert ret_msg.message_id
def test_send_video_more_params(self):
file_data = open('./test_data/test_video.mp4', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_video(CHAT_ID, file_data, 1)
assert ret_msg.message_id
def test_send_video_more_params_dis_noti(self):
file_data = open('./test_data/test_video.mp4', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_video(CHAT_ID, file_data, 1, disable_notification=True)
assert ret_msg.message_id
def test_send_file_exception(self):
tb = telebot.TeleBot(TOKEN)
try:
tb.send_document(CHAT_ID, None)
assert False
except Exception as e:
print(e)
assert True
def test_send_photo(self):
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_photo(CHAT_ID, file_data)
assert ret_msg.message_id
ret_msg = tb.send_photo(CHAT_ID, ret_msg.photo[0].file_id)
assert ret_msg.message_id
def test_send_photo_dis_noti(self):
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_photo(CHAT_ID, file_data)
assert ret_msg.message_id
ret_msg = tb.send_photo(CHAT_ID, ret_msg.photo[0].file_id, disable_notification=True)
assert ret_msg.message_id
def test_send_audio(self):
file_data = open('./test_data/record.mp3', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_audio(CHAT_ID, file_data, 1, performer='eternnoir', title='pyTelegram')
assert ret_msg.content_type == 'audio'
assert ret_msg.audio.performer == 'eternnoir'
assert ret_msg.audio.title == 'pyTelegram'
def test_send_audio_dis_noti(self):
file_data = open('./test_data/record.mp3', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_audio(CHAT_ID, file_data, 1, performer='eternnoir', title='pyTelegram', disable_notification=True)
assert ret_msg.content_type == 'audio'
assert ret_msg.audio.performer == 'eternnoir'
assert ret_msg.audio.title == 'pyTelegram'
def test_send_voice(self):
file_data = open('./test_data/record.ogg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_voice(CHAT_ID, file_data)
assert ret_msg.voice.mime_type == 'audio/ogg'
def test_send_voice_dis_noti(self):
file_data = open('./test_data/record.ogg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_voice(CHAT_ID, file_data, disable_notification=True)
assert ret_msg.voice.mime_type == 'audio/ogg'
def test_get_file(self):
file_data = open('./test_data/record.ogg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_voice(CHAT_ID, file_data)
file_id = ret_msg.voice.file_id
file_info = tb.get_file(file_id)
assert file_info.file_id == file_id
def test_get_file_dis_noti(self):
file_data = open('./test_data/record.ogg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_voice(CHAT_ID, file_data, disable_notification=True)
file_id = ret_msg.voice.file_id
file_info = tb.get_file(file_id)
assert file_info.file_id == file_id
def test_send_message(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_message(CHAT_ID, text)
assert ret_msg.message_id
def test_send_message_dis_noti(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_message(CHAT_ID, text, disable_notification=True)
assert ret_msg.message_id
def test_send_message_with_markup(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
markup = types.ReplyKeyboardMarkup()
markup.add(types.KeyboardButton("1"))
markup.add(types.KeyboardButton("2"))
ret_msg = tb.send_message(CHAT_ID, text, disable_notification=True, reply_markup=markup)
assert ret_msg.message_id
def test_send_message_with_markup_use_string(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
markup = types.ReplyKeyboardMarkup()
markup.add("1")
markup.add("2")
markup.add("3")
markup.add("4")
ret_msg = tb.send_message(CHAT_ID, text, disable_notification=True, reply_markup=markup)
assert ret_msg.message_id
def test_send_message_with_inlinemarkup(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton("Google", url="http://www.google.com"))
markup.add(types.InlineKeyboardButton("Yahoo", url="http://www.yahoo.com"))
ret_msg = tb.send_message(CHAT_ID, text, disable_notification=True, reply_markup=markup)
assert ret_msg.message_id
def test_forward_message(self):
text = 'CI forward_message Test Message'
tb = telebot.TeleBot(TOKEN)
msg = tb.send_message(CHAT_ID, text)
ret_msg = tb.forward_message(CHAT_ID, CHAT_ID, msg.message_id)
assert ret_msg.forward_from
def test_forward_message_dis_noti(self):
text = 'CI forward_message Test Message'
tb = telebot.TeleBot(TOKEN)
msg = tb.send_message(CHAT_ID, text)
ret_msg = tb.forward_message(CHAT_ID, CHAT_ID, msg.message_id, disable_notification=True)
assert ret_msg.forward_from
def test_reply_to(self):
text = 'CI reply_to Test Message'
tb = telebot.TeleBot(TOKEN)
msg = tb.send_message(CHAT_ID, text)
ret_msg = tb.reply_to(msg, text + ' REPLY')
assert ret_msg.reply_to_message.message_id == msg.message_id
def test_register_for_reply(self):
text = 'CI reply_to Test Message'
tb = telebot.TeleBot(TOKEN)
msg = tb.send_message(CHAT_ID, text, reply_markup=types.ForceReply())
reply_msg = tb.reply_to(msg, text + ' REPLY')
def process_reply(message):
assert msg.message_id == message.reply_to_message.message_id
tb.register_for_reply(msg, process_reply)
tb.process_new_messages([reply_msg])
def test_send_location(self):
tb = telebot.TeleBot(TOKEN)
lat = 26.3875591
lon = -161.2901042
ret_msg = tb.send_location(CHAT_ID, lat, lon)
assert int(ret_msg.location.longitude) == int(lon)
assert int(ret_msg.location.latitude) == int(lat)
def test_send_location_dis_noti(self):
tb = telebot.TeleBot(TOKEN)
lat = 26.3875591
lon = -161.2901042
ret_msg = tb.send_location(CHAT_ID, lat, lon, disable_notification=True)
assert int(ret_msg.location.longitude) == int(lon)
assert int(ret_msg.location.latitude) == int(lat)
def test_send_venue(self):
tb = telebot.TeleBot(TOKEN)
lat = 26.3875591
lon = -161.2901042
ret_msg = tb.send_venue(CHAT_ID, lat, lon, "Test Venue", "1123 Test Venue address")
assert ret_msg.venue.title == "Test Venue"
assert int(lat) == int(ret_msg.venue.location.latitude)
def test_send_venue_dis_noti(self):
tb = telebot.TeleBot(TOKEN)
lat = 26.3875591
lon = -161.2901042
ret_msg = tb.send_venue(CHAT_ID, lat, lon, "Test Venue", "1123 Test Venue address", disable_notification=True)
assert ret_msg.venue.title == "Test Venue"
def test_Chat(self):
tb = telebot.TeleBot(TOKEN)
me = tb.get_me()
msg = tb.send_message(CHAT_ID, 'Test')
assert me.id == msg.from_user.id
assert msg.chat.id == int(CHAT_ID)
def test_edit_message_text(self):
tb = telebot.TeleBot(TOKEN)
msg = tb.send_message(CHAT_ID, 'Test')
new_msg = tb.edit_message_text('Edit test', chat_id=CHAT_ID, message_id=msg.message_id)
assert new_msg.text == 'Edit test'
def test_edit_message_caption(self):
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
tb = telebot.TeleBot(TOKEN)
msg = tb.send_document(CHAT_ID, file_data, caption="Test")
new_msg = tb.edit_message_caption(caption='Edit test', chat_id=CHAT_ID, message_id=msg.message_id)
assert new_msg.caption == 'Edit test'
def test_get_chat(self):
tb = telebot.TeleBot(TOKEN)
ch = tb.get_chat(GROUP_ID)
assert str(ch.id) == GROUP_ID
def test_get_chat_administrators(self):
tb = telebot.TeleBot(TOKEN)
cas = tb.get_chat_administrators(GROUP_ID)
assert len(cas) > 0
def test_get_chat_members_count(self):
tb = telebot.TeleBot(TOKEN)
cn = tb.get_chat_members_count(GROUP_ID)
assert cn > 1
def test_edit_markup(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton("Google", url="http://www.google.com"))
markup.add(types.InlineKeyboardButton("Yahoo", url="http://www.yahoo.com"))
ret_msg = tb.send_message(CHAT_ID, text, disable_notification=True, reply_markup=markup)
markup.add(types.InlineKeyboardButton("Google2", url="http://www.google.com"))
markup.add(types.InlineKeyboardButton("Yahoo2", url="http://www.yahoo.com"))
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):
params = {'text': text}
chat = types.User(11, 'test')
return types.Message(1, None, None, chat, 'text', params)
def test_is_string_unicode(self):
s1 = u'string'
assert util.is_string(s1)
def test_is_string_string(self):
s1 = 'string'
assert util.is_string(s1)
def test_not_string(self):
i1 = 10
assert not util.is_string(i1)
def test_send_video_note(self):
file_data = open('./test_data/test_video.mp4', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_video_note(CHAT_ID, file_data)
assert ret_msg.message_id

View File

@ -12,17 +12,17 @@ def test_json_user():
def test_json_message():
jsonstring = r'{"message_id":1,"from":{"id":108929734,"first_name":"Frank","last_name":"Wang","username":"eternnoir"},"chat":{"id":108929734,"first_name":"Frank","last_name":"Wang","username":"eternnoir"},"date":1435296025,"text":"HIHI"}'
jsonstring = r'{"message_id":1,"from":{"id":108929734,"first_name":"Frank","last_name":"Wang","username":"eternnoir"},"chat":{"id":1734,"first_name":"F","type":"private","last_name":"Wa","username":"oir"},"date":1435296025,"text":"HIHI"}'
msg = types.Message.de_json(jsonstring)
assert msg.text == 'HIHI'
def test_json_message_group():
json_string = r'{"message_id":10,"from":{"id":12345,"first_name":"g","last_name":"G","username":"GG"},"chat":{"id":-866,"title":"\u4ea4"},"date":1435303157,"text":"HIHI"}'
json_string = r'{"message_id":10,"from":{"id":12345,"first_name":"g","last_name":"G","username":"GG"},"chat":{"id":-866,"type":"private","title":"\u4ea4"},"date":1435303157,"text":"HIHI"}'
msg = types.Message.de_json(json_string)
assert msg.text == 'HIHI'
assert len(msg.chat.title) != 0
assert msg.fromUser.username == 'GG'
assert msg.from_user.username == 'GG'
def test_json_GroupChat():
@ -39,36 +39,46 @@ def test_json_Document():
def test_json_Message_Audio():
json_string = r'{"message_id":100,"from":{"id":10734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":10734,"first_name":"dd","last_name":"dd","username":"dd"},"date":1435481343,"audio":{"duration":3,"mime_type":"audio\/ogg","file_id":"ddg","file_size":8249}}'
json_string = r'{"message_id":131,"from":{"id":12775,"first_name":"dd","username":"dd"},"chat":{"id":10834,"first_name":"dd","type":"private","type":"private","last_name":"dd","username":"dd"},"date":1439978364,"audio":{"duration":1,"mime_type":"audio\/mpeg","title":"pyTelegram","performer":"eternnoir","file_id":"BQADBQADDH1JaB8-1KyWUss2-Ag","file_size":20096}}'
msg = types.Message.de_json(json_string)
assert msg.audio.duration == 3
assert msg.audio.duration == 1
assert msg.content_type == 'audio'
assert msg.audio.performer == 'eternnoir'
assert msg.audio.title == 'pyTelegram'
def test_json_Message_Sticker():
json_string = r'{"message_id":98,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","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"},"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}}'
msg = types.Message.de_json(json_string)
assert msg.sticker.height == 368
assert msg.sticker.thumb.height == 60
assert msg.content_type == 'sticker'
def test_json_Message_Sticker_without_thumb():
json_string = r'{"message_id":98,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435479551,"sticker":{"width":550,"height":368,"file_id":"BQADBQADNAIAAsYifgYdGJOa6bGAsQI","file_size":30320}}'
msg = types.Message.de_json(json_string)
assert msg.sticker.height == 368
assert msg.sticker.thumb == None
assert msg.content_type == 'sticker'
def test_json_Message_Document():
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10,"first_name":"Fd","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_size":446}}'
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_size":446}}'
msg = types.Message.de_json(json_string)
assert msg.document.file_name == 'Text File'
assert msg.content_type == 'document'
def test_json_Message_Photo():
json_string = r'{"message_id":96,"from":{"id":109734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","last_name":"dd","username":"dd"},"date":1435478191,"photo":[{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":615,"width":90,"height":67},{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":10174,"width":320,"height":240},{"file_id":"dd-A_LsTIABFNx-FUOaEa_3AABAQABAg","file_size":53013,"width":759,"height":570}]}'
json_string = r'{"message_id":96,"from":{"id":109734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"dd","username":"dd"},"date":1435478191,"photo":[{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":615,"width":90,"height":67},{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":10174,"width":320,"height":240},{"file_id":"dd-A_LsTIABFNx-FUOaEa_3AABAQABAg","file_size":53013,"width":759,"height":570}]}'
msg = types.Message.de_json(json_string)
assert len(msg.photo) == 3
assert msg.content_type == 'photo'
def test_json_Message_Video():
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_size":260699}}'
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_size":260699}}'
msg = types.Message.de_json(json_string)
assert msg.video
assert msg.video.duration == 3
@ -77,7 +87,7 @@ def test_json_Message_Video():
def test_json_Message_Location():
json_string = r'{"message_id":102,"from":{"id":108734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":1089734,"first_name":"dd","last_name":"dd","username":"dd"},"date":1535482469,"location":{"longitude":127.479471,"latitude":26.090577}}'
json_string = r'{"message_id":102,"from":{"id":108734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":1089734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1535482469,"location":{"longitude":127.479471,"latitude":26.090577}}'
msg = types.Message.de_json(json_string)
assert msg.location.latitude == 26.090577
assert msg.content_type == 'location'
@ -95,3 +105,53 @@ def test_json_contact():
contact = types.Contact.de_json(json_string)
assert contact.first_name == 'dd'
assert contact.last_name == 'ddl'
def test_json_voice():
json_string = r'{"duration": 0,"mime_type": "audio/ogg","file_id": "AwcccccccDH1JaB7w_gyFjYQxVAg","file_size": 10481}'
voice = types.Voice.de_json(json_string)
assert voice.duration == 0
assert voice.file_size == 10481
def test_json_update():
json_string = r'{"update_id":938203,"message":{"message_id":241,"from":{"id":9734,"first_name":"Fk","last_name":"Wg","username":"nir"},"chat":{"id":1111,"first_name":"Fk","type":"private","last_name":"Wg","username":"oir"},"date":1441447009,"text":"HIHI"}}'
update = types.Update.de_json(json_string)
assert update.update_id == 938203
assert update.message.message_id == 241
assert update.message.from_user.id == 9734
def test_json_chat():
json_string = r'{"id": -111111,"title": "Test Title","type": "group"}'
chat = types.Chat.de_json(json_string)
assert chat.id == -111111
assert chat.type == 'group'
assert chat.title == 'Test Title'
def test_InlineQueryResultCachedPhoto():
iq = types.InlineQueryResultCachedPhoto('aaa', 'Fileid')
json_str = iq.to_json()
assert 'aa' in json_str
assert 'Fileid' in json_str
assert 'caption' not in json_str
def test_InlineQueryResultCachedPhoto_with_title():
iq = types.InlineQueryResultCachedPhoto('aaa', 'Fileid', title='Title')
json_str = iq.to_json()
assert 'aa' in json_str
assert 'Fileid' in json_str
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"))
markup.add(types.InlineKeyboardButton("Yahoo", url="http://www.yahoo.com"))
iq = types.InlineQueryResultCachedPhoto('aaa', 'Fileid', title='Title', reply_markup=markup)
json_str = iq.to_json()
assert 'aa' in json_str
assert 'Fileid' in json_str
assert 'Title' in json_str
assert 'caption' not in json_str
assert 'reply_markup' in json_str