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

Compare commits

...

1278 Commits
1.4.1 ... 4.2.1

Author SHA1 Message Date
fbf34f5953 Bump version to 4.2.1 - AsyncTeleBot alpha 2021-12-04 20:25:39 +03:00
4347dd3dd9 Merge pull request #1380 from coder2020official/master
2 new examples and behaviour change
2021-12-04 20:08:26 +03:00
d830ae0b15 Merge branch 'master' of https://github.com/coder2020official/pyTelegramBotAPI 2021-12-04 22:03:56 +05:00
4f198bc6f5 Forgot to update file 2021-12-04 22:03:14 +05:00
66615a41c4 Merge branch 'eternnoir:master' into master 2021-12-04 21:57:32 +05:00
a5ee5f816c Update README.md 2021-12-04 21:57:16 +05:00
fb52137bff 2 new examples 2021-12-04 21:54:26 +05:00
7ee07f4dc7 Merge pull request #1379 from Badiboy/master
Readme
2021-12-04 19:44:00 +03:00
f224069a34 Update README.md 2021-12-04 19:43:33 +03:00
6cca77f755 Update README.md 2021-12-04 19:43:01 +03:00
084289baa4 Merge pull request #1378 from Badiboy/master
Readme minor fixed
2021-12-04 19:42:08 +03:00
e2dbb88459 Readme minor fixed 2021-12-04 19:41:25 +03:00
a2822c74ed Update README.md 2021-12-04 21:34:15 +05:00
4cd30c75ac Merge pull request #1377 from coder2020official/master
Exception handler, Boolean Fix and more
2021-12-04 19:33:53 +03:00
f4b9480588 Update README.md 2021-12-04 21:25:47 +05:00
482589af49 Update README.md 2021-12-04 21:25:14 +05:00
bbe4a96984 Update README.md 2021-12-04 21:23:23 +05:00
60294d0c41 Update README.md 2021-12-04 21:22:44 +05:00
3035763277 Update send_file_example.py 2021-12-04 21:22:00 +05:00
51eabde320 Update 2021-12-04 21:11:51 +05:00
a5305f551c Update README.md 2021-12-03 21:13:02 +05:00
1f918dece5 Merge pull request #1375 from coder2020official/master
Forgot to make polling sync
2021-11-27 23:12:15 +03:00
fc152f37ad Merge branch 'eternnoir:master' into master 2021-11-28 01:05:11 +05:00
411c7e915a No asyncio.run() 2021-11-28 01:04:49 +05:00
5bf2415653 Merge pull request #1374 from Badiboy/master
Python 3.10 added
2021-11-27 22:30:25 +03:00
7d9856dae3 Python 3.10 added 2021-11-27 22:29:57 +03:00
a308ab12fa Asynchronous TeleBot version Alpha release 2021-11-27 22:28:46 +03:00
d58336adcb Fix 2021-11-28 00:25:56 +05:00
bfc0b8ecd5 Update async_telebot.py 2021-11-28 00:21:09 +05:00
a9b422783f Middlewares, new file, and examples 2021-11-27 23:41:39 +05:00
e015b4c010 Merge pull request #1373 from Carlosma7/master
Add GrandQuiz Bot by Carlosma7
2021-11-27 18:49:05 +03:00
f666c15a1f Add GrandQuiz Bot by Carlosma7 2021-11-27 16:32:58 +01:00
6770011dd7 Middleware support 2021-11-27 19:04:03 +05:00
d7b0513fb1 Merge branch 'eternnoir:master' into master 2021-11-26 21:05:05 +05:00
9932ade00e Merge pull request #1369 from abdullaev388/master
CallbackData class added
2021-11-24 18:32:42 +03:00
8b6eba8203 Docstrings added 2021-11-24 20:26:58 +05:00
9c8ea29fc6 token removed :) 2021-11-23 18:15:52 +05:00
714ae7d67f CallbackData class added 2021-11-23 18:01:51 +05:00
1e4477c148 Logging fix 2021-11-20 16:01:38 +05:00
53f9232f36 Update requirements.txt 2021-11-20 15:54:43 +05:00
1f05b47ad6 Asynchronous Telebot 2021-11-20 15:47:55 +05:00
98d63d235f Merge pull request #1360 from JoachimStanislaus/master
added Google Sheet bot to list of bot examples.
2021-11-11 12:40:36 +03:00
7925bdc6c9 added Google Sheet bot to list of bot examples. 2021-11-11 17:21:56 +08:00
4ba23562ef Merge pull request #1358 from Badiboy/master
Update readme and typo
2021-11-08 19:11:11 +03:00
e22a7fecea One more readme update... 2021-11-08 18:53:10 +03:00
9b99bb5f21 Update readme and typo 2021-11-08 18:51:42 +03:00
c39b3aaaf3 Merge pull request #1357 from Badiboy/master
Bump to version 4.2.0
2021-11-08 18:37:03 +03:00
d14ac2fe85 Bump to version 4.2.0 2021-11-08 18:35:55 +03:00
04f3e518da Merge remote-tracking branch 'upstream/master' 2021-11-08 18:33:10 +03:00
5f5298bcd1 Merge pull request #1356 from Badiboy/master
RETRY_ENGINE
2021-11-08 18:33:00 +03:00
7f1497c5e9 Merge remote-tracking branch 'upstream/master' 2021-11-08 18:32:38 +03:00
5ac71baafe RETRY_ENGINE
Added RETRY_ENGINE var to api_helper.

Added RETRY_ENGINE = 2 based on native "requests" retry mechanism.
2021-11-07 23:02:23 +03:00
695c699893 Merge pull request #1353 from coder2020official/master
Bot API 5.4 features
2021-11-06 18:02:01 +03:00
bf96f13296 Merge branch 'master' of https://github.com/coder2020official/pyTelegramBotAPI 2021-11-06 19:59:59 +05:00
62b1ec04ab Update __init__.py 2021-11-06 19:59:44 +05:00
e412d2f084 Update README.md 2021-11-06 19:56:10 +05:00
8003ff5e59 Delete states.pkl 2021-11-06 19:51:29 +05:00
becce1f580 Update apihelper.py 2021-11-06 19:51:05 +05:00
3a6073e3a0 Update custom_states.py 2021-11-06 13:08:49 +05:00
fc347ae166 Update custom_states.py 2021-11-06 13:06:43 +05:00
8dcfa0c282 Little fix for states 2021-11-06 12:52:41 +05:00
6808ab3ebe Update test_types.py 2021-11-06 12:42:48 +05:00
31097c5380 Update test_types.py 2021-11-06 12:34:49 +05:00
d49c57699e Tests 2021-11-06 12:27:19 +05:00
ed6616e4c7 Bot API 5.4 2021-11-06 12:21:02 +05:00
953e2286b8 Bot API 5.4 2021-11-06 12:15:28 +05:00
06c8782127 Little update
Allowed other handlers, checked methods and other things
2021-11-05 23:22:03 +05:00
2623fa362c Merge pull request #1350 from Badiboy/master
Custom request sender
2021-11-03 18:50:25 +03:00
4a274ba440 Custom request sender
Added apihelper.CUSTOM_REQUEST_SENDER option. It allows to substitute requests.request to your own function.
2021-11-03 18:48:46 +03:00
bfef7e1ce2 Merge pull request #1349 from barbax7/antiflood
Antiflood
2021-11-03 17:38:32 +03:00
558b37b1c3 New antiflood function 2021-11-03 15:30:10 +01:00
d1c26f82aa Merge pull request #1346 from DevAdvik/patch-1
Added A New Bot - @ETHGasFeeTrackerBot
2021-10-24 19:09:04 +03:00
1a351bc8c7 Added A New Bot 2021-10-24 20:38:15 +05:30
27546daad9 Merge pull request #1345 from resinprotein2333/patch-1
Update README.md
2021-10-24 11:48:02 +03:00
bb58d3fead Update README.md
Add my bot into the bot list
2021-10-24 16:45:49 +08:00
099d638a7e Merge pull request #1338 from barbax7/exceptions
Added description of the ApiTelegramException as attribute of the class
2021-10-17 11:29:44 +03:00
5fb48e68a0 Added description of the ApiTelegramException as attribute of the class 2021-10-16 17:45:15 +02:00
b979c2fa1f Merge pull request #1336 from coder2020official/master
File support for states
2021-10-14 17:23:43 +03:00
b6625baec6 Update __init__.py 2021-10-13 19:02:17 +05:00
98044d6faa File support for states
File support. Now states can be saved in pickle file
2021-10-13 18:34:36 +05:00
2113846567 Merge pull request #1330 from Badiboy/master
Bump version 4.1.1
2021-10-09 22:31:59 +03:00
5c9d4edca9 Bump version 4.1.1 2021-10-09 22:31:34 +03:00
4dce9340b0 Merge pull request #1326 from TrevorWinstral/master
Added my bots to README
2021-10-08 13:45:24 +03:00
bf79e8341e Moved bots to bottom of list 2021-10-08 10:39:59 +00:00
dadfdc2f13 Updated README with my bots 2021-10-06 14:15:30 +02:00
585f627e1f Updated README with my bots 2021-10-06 14:14:05 +02:00
eead303d47 Updated README with my bots 2021-10-06 14:13:05 +02:00
14cc15c711 Merge pull request #1325 from coder2020official/master
Critical fix
2021-10-01 21:47:50 +03:00
bf8736e17e Critical fix 2021-10-01 23:29:59 +05:00
5014ca2459 Merge pull request #1324 from coder2020official/master
Update of state handlers
2021-10-01 14:55:09 +03:00
f337abe06e Update __init__.py 2021-10-01 16:09:20 +05:00
ff35f25211 Update __init__.py 2021-10-01 16:08:01 +05:00
2e4280a947 Update of state handlers
No need to create state handlers
2021-10-01 15:56:54 +05:00
4a6b5b3d28 Merge pull request #1322 from Badiboy/master
Bugfix with one_time_keyboard = False
2021-09-30 11:57:54 +03:00
a28af3903d Bugfix with one_time_keyboard = False 2021-09-30 11:56:36 +03:00
d1d5b9effb Merge pull request #1320 from Badiboy/master
polling should leave our world. :)
2021-09-28 19:18:32 +03:00
062fababf2 polling should leave our world. :) 2021-09-28 19:17:09 +03:00
946afcc3c1 Merge pull request #1317 from coder2020official/master
Update handler_backends.py
2021-09-25 21:35:25 +03:00
6e502cd1c6 Merge branch 'master' into master 2021-09-25 23:29:50 +05:00
0a7f897f05 Merge pull request #1318 from Badiboy/master
States minor update
2021-09-25 21:15:52 +03:00
b35f17124f States minor update 2021-09-25 21:15:24 +03:00
44b44ac2c5 Optimization 2021-09-25 23:05:36 +05:00
39e875c1ea Update handler_backends.py 2021-09-25 22:49:32 +05:00
be7317cc86 Merge pull request #1315 from coder2020official/master
States, New filter, and more
2021-09-25 20:43:33 +03:00
e1c33a1de6 Merge pull request #1316 from Badiboy/master
Release 4.1.0
2021-09-25 20:34:05 +03:00
8149551a15 Release 4.1.0 2021-09-25 20:33:32 +03:00
ab648ef3db Merge branch 'master' of https://github.com/coder2020official/pyTelegramBotAPI 2021-09-25 22:19:09 +05:00
e721910c0c Update __init__.py 2021-09-25 22:19:07 +05:00
9287eced49 Update a typo 2021-09-25 21:10:29 +05:00
967b94b14f Update handler_backends.py 2021-09-25 20:27:03 +05:00
2df6f00ba5 Optimization
Optimized code, added filters support
2021-09-25 18:22:54 +05:00
beb4f8df44 Update register_handler.py 2021-09-25 17:15:33 +05:00
92ac5a4166 States, and some minor improvements 2021-09-25 17:12:32 +05:00
716323e56a Register_XXX_Handler 2021-09-22 22:46:19 +05:00
cd92d95f91 Create admin_filter_example.py 2021-09-22 22:37:57 +05:00
9c86ed623d Update custom_filters.py 2021-09-22 22:37:18 +05:00
c6ff9b07df Merge pull request #1311 from SwissCorePy/master
added property `user` to TeleBot class
2021-09-20 15:40:14 +03:00
38cc96d0f3 added property user to TeleBot class
Added property `user` to TeleBot class. The idea is to have easy access to the user object representing the bot without doing an API call every time.
2021-09-20 14:31:00 +02:00
82518d8664 Merge pull request #1309 from bim-ba/master
Added new example: anonymous chat-bot
2021-09-19 17:50:51 +03:00
aba2a9e179 Improve readabilty of "elif-zone" 2021-09-19 17:41:07 +03:00
c5c4d081ea Added new example: anonymous chat-bot 2021-09-18 19:46:53 +03:00
f854163626 Merge pull request #1308 from coder2020official/master
Added example and editd description.
2021-09-14 13:08:45 +03:00
fc31a2d466 Update custom_filters.py 2021-09-14 15:02:54 +05:00
86a0a8cd68 Little fixes and example
Fixed is_forwarded custom filter & created example
2021-09-14 15:00:27 +05:00
31c3b3b28e Merge pull request #1307 from coder2020official/master
Update custom_filters.py
2021-09-13 23:26:40 +03:00
b95ab104e3 Update custom_filters.py 2021-09-13 23:09:06 +05:00
a54e4c22a8 Merge pull request #1305 from Badiboy/master
4.0.1 beta release
2021-09-12 21:13:38 +03:00
7913e25be2 4.0.1 beta release 2021-09-12 21:12:19 +03:00
63cbda8890 Merge pull request #1304 from Badiboy/master
README contents update
2021-09-12 20:53:04 +03:00
38851bce22 README contents update 2021-09-12 20:02:49 +03:00
74835c40ea Merge pull request #1303 from Badiboy/master
Update custom filters readme and examples
2021-09-12 19:42:36 +03:00
97e99b4910 Fix 2021-09-12 19:39:26 +03:00
4ced4d29f5 Update custom filters readme and examples 2021-09-12 19:36:23 +03:00
239a90de14 Merge pull request #1302 from coder2020official/master
Some useful filters
2021-09-12 19:14:46 +03:00
c86af0496b Update README.md 2021-09-12 20:43:09 +05:00
4071ab9124 Update README.md 2021-09-12 20:41:26 +05:00
5c715dabc3 Update README.md 2021-09-12 20:40:31 +05:00
43d2d8583e Update README.md 2021-09-12 20:32:16 +05:00
cf78234e3a Update README.md 2021-09-12 20:30:32 +05:00
5f4cd09490 Update README.md 2021-09-12 20:28:46 +05:00
8534804c0c Update README.md 2021-09-12 20:28:01 +05:00
cf75e76e5c Update README.md 2021-09-12 20:27:01 +05:00
7d5e9e5111 Added file custom_filters
Added file with custom filters. Updated the examples
2021-09-12 20:22:26 +05:00
1ceec3cb54 Update custom_filters.py 2021-09-12 19:38:54 +05:00
5f8c75816e Some useful filters
Created useful filters that can be used in message handlers.
Created some examples on using them.
2021-09-12 19:34:43 +05:00
4e37662ab3 upd 2021-09-12 00:30:56 +05:00
a97a917522 Merge pull request #1301 from coder2020official/master
Custom filters example
2021-09-11 22:30:50 +03:00
88f91518c7 Update __init__.py 2021-09-12 00:27:51 +05:00
e89acc8ba6 Update custom_filters.py 2021-09-12 00:27:04 +05:00
5d611ea7f3 upd 2021-09-12 00:24:52 +05:00
5c80f11261 Updated __init__.py 2021-09-12 00:21:35 +05:00
f2202b44fe Merge pull request #1300 from Badiboy/master
Custom filters upd
2021-09-11 21:51:09 +03:00
2da48c0adc Custom filters upd 2021-09-11 21:49:51 +03:00
389407e3ee Merge pull request #1299 from Badiboy/master
Custom filters upd
2021-09-11 21:14:43 +03:00
14be2b8c18 Custom filters upd 2021-09-11 21:10:21 +03:00
df7808264f Merge pull request #1298 from coder2020official/master
Custom filters
2021-09-11 21:03:28 +03:00
9d37503442 reupdated 2021-09-11 23:02:56 +05:00
dd6f39c3cd Merge pull request #1296 from Badiboy/master
Filter clearance
2021-09-11 20:57:55 +03:00
8e4d70b9c6 Update __init__.py 2021-09-11 22:30:53 +05:00
87fb30d57b Update __init__.py 2021-09-11 22:03:37 +05:00
8f3371dcd5 Update __init__.py 2021-09-11 21:59:28 +05:00
ec8975c9e3 Custom filters
Added new feature - from now you can create your own custom filters
2021-09-11 21:47:59 +05:00
16edfbb9dc Warning if commands or content_types filters are strings 2021-09-11 19:26:55 +03:00
f70b135359 Filter clearance
1. Filter optimization: should not store empty filters
2. Filter order: chat_type, content, others
3. Default session timeout set to 600 instead of "forever".
4. Type
2021-09-11 17:02:40 +03:00
78fb69ded1 Merge pull request #1295 from coder2020official/master
is_private filter
2021-09-10 22:17:05 +03:00
0f7eb1571e Update README.md 2021-09-10 20:42:48 +05:00
ac54b7abd4 Merge branch 'master' of https://github.com/coder2020official/pyTelegramBotAPI 2021-09-10 20:42:51 +05:00
0f3a6393fc Update __init__.py 2021-09-10 20:42:43 +05:00
de6f339cdf Update README.md 2021-09-10 17:57:19 +05:00
d0969bd5f3 Merge branch 'master' of https://github.com/coder2020official/pyTelegramBotAPI 2021-09-10 17:57:13 +05:00
4035a38507 Update __init__.py 2021-09-10 17:56:44 +05:00
944b077c65 Update README.md 2021-09-10 17:30:58 +05:00
644c6b9082 is_private 2021-09-10 17:30:17 +05:00
dc9f8db556 Merge pull request #1288 from SwissCorePy/master
Added missing content_type "animation"
2021-09-02 22:34:51 +03:00
07ebdeab25 Added missing content_type "animation" 2021-09-02 19:46:01 +02:00
e8738cce7d Merge pull request #1284 from Badiboy/master
Bump version to 4.0 release
2021-08-30 13:50:32 +03:00
d9e638a7df Bump version to 4.0 release 2021-08-30 13:49:28 +03:00
08b1dd31c8 Merge pull request #1277 from fgallaire/master
A Google Cloud Functions webhook
2021-08-25 15:19:51 +03:00
b4f0a6d546 add Google in the name 2021-08-25 14:17:25 +02:00
4eb28df1ab A Google Cloud Functions webhook 2021-08-24 13:01:10 +02:00
50e5e96bb1 Merge pull request #1275 from Badiboy/master
chat_invite_link bugfix
2021-08-22 22:17:30 +03:00
bd3a9bc350 chat_invite_link bugfix 2021-08-22 22:16:03 +03:00
06923c8274 Merge pull request #1272 from Badiboy/master
Simplify and speedup _test_filter
2021-08-20 15:55:10 +03:00
3efc2cf869 Typo 2021-08-19 23:36:37 +03:00
f5de0eeacf Simplify and speedup _test_filter 2021-08-19 22:46:12 +03:00
6e871b8eb1 Merge pull request #1270 from Badiboy/master
Check and update for full compatibility to Bot API up to 5.3
2021-08-18 23:31:15 +03:00
f6359bc32c Readme fix 2021-08-18 23:29:40 +03:00
2bc052ad5a Check and update for full compatibility to Bot API up to 5.3
Pre-release of 4.0.0
2021-08-18 23:27:28 +03:00
022ef6a64c Dependecies clearing 2021-08-18 22:16:30 +03:00
3232811543 Merge pull request #1269 from Badiboy/master
Check and update for full compatibility to Bot API up to 5.0
2021-08-18 22:01:12 +03:00
fabcd93dd7 API update fix 03 2021-08-18 21:57:56 +03:00
8053183cb5 API update fix 02 2021-08-18 19:36:48 +03:00
b2b7d90888 API update fix 01 2021-08-18 19:32:43 +03:00
3e9d73c25d Merge remote-tracking branch 'upstream/master' 2021-08-18 18:52:09 +03:00
d6501ddc0e Check and update for full compatibility to Bot API up to 5.0 2021-08-18 18:47:38 +03:00
e818e3875d Merge pull request #1266 from coder2020official/master
New set of register_xxx_handler functions for dynamic handlers registering.
2021-08-17 16:50:00 +03:00
56cd3971dc Update __init__.py 2021-08-16 22:41:27 +04:00
958ca34e9c Merge pull request #1264 from coder2020official/master
Added skip_pending parameter to polling and infinity_polling in addition to skip_pending in Telebot.Init. Allows skip pending updates for already created Bot instances.
2021-08-16 21:07:41 +03:00
f4ef2366b6 Update skip_updates_example.py 2021-08-16 22:03:17 +04:00
f553960096 Update __init__.py 2021-08-16 22:00:08 +04:00
24ef64456b Update __init__.py 2021-08-16 14:53:00 +04:00
3e7da0fd18 Update skip_updates_example.py 2021-08-16 14:49:45 +04:00
2c0f42b363 Update __init__.py 2021-08-16 14:48:21 +04:00
1e4a6e2125 Update __init__.py 2021-08-15 13:32:11 +04:00
beeb60aab8 skip_updates 2021-08-15 11:40:13 +04:00
5b942a5b31 Merge pull request #1263 from coder2020official/master
Create chat_member_example.py
2021-08-14 17:55:15 +03:00
3e4a6cd702 Create chat_member_example.py 2021-08-14 18:46:45 +04:00
0e369953cb Merge pull request #1261 from Badiboy/master
BotCommandScopeChatMember fix
2021-08-12 15:17:11 +03:00
911e356930 BotCommandScopeChatMember fix 2021-08-12 15:16:04 +03:00
554b39a49a Merge pull request #1257 from AmolDerickSoans/master
Add IPO bot
2021-08-06 14:48:51 +03:00
ea16f35432 Add IPO bot
Listed oneIPO bot created using pyTelegramBotAPI in  section : Bpts using this API
2021-08-06 12:29:00 +05:30
81d94687be Merge pull request #1254 from snikidev/bug/InputInvoiceMessageContent-return-statement
🐛 Bugfix: Add return statement to to_dict() method inside InputInvoiceMessageContent type
2021-08-03 21:03:38 +03:00
4ba4bc18cf add extra space 2021-08-03 17:35:59 +01:00
c117ff2d50 Add return statement to to_dict() method inside InputInvoiceMessageContent 2021-08-03 17:34:29 +01:00
735c224444 Merge pull request #1248 from coder2020official/master
caption_entities in edit_message_caption
2021-07-30 19:11:05 +03:00
81adfd335e UPD 2021-07-30 19:15:37 +05:00
7ebe589b46 Update __init__.py 2021-07-28 23:10:15 +05:00
9c1b19a9e4 upd 2021-07-28 23:06:31 +05:00
02b886465e new filters 2021-07-25 15:46:53 +05:00
2d89ceb745 Merge pull request #1241 from Badiboy/master
Release version 3.8.2
2021-07-21 21:54:29 +03:00
ae8c3252df Release version 3.8.2 2021-07-21 21:53:56 +03:00
7914f71938 Merge pull request #1237 from monosans/comprehension
Replace for loops with comprehensions
2021-07-19 23:40:55 +03:00
097ba9fec2 Replace for loops with comprehensions 2021-07-19 20:03:03 +03:00
d09d9f0c09 Merge pull request #1232 from Badiboy/master
Invoice tips typo fix
2021-07-15 09:27:49 +03:00
29c98b0230 Invoice tips typo fix 2021-07-15 09:27:07 +03:00
2b1db1f1b3 Merge pull request #1231 from vnagornyy/master
Added tip for invoice
2021-07-15 09:23:10 +03:00
fa80b1dba0 Added tip for invoice 2021-07-15 08:56:04 +03:00
b45db584df Merge pull request #1230 from Badiboy/master
Fix worker_pool issue
2021-07-13 22:16:48 +03:00
f52ea635e5 Fix worker_pool issue 2021-07-13 22:09:56 +03:00
9b56afd569 Merge pull request #1229 from Badiboy/master
Fix CallbackQuery issue for games
2021-07-13 20:13:36 +03:00
6fb10e92e4 Fix CallbackQuery issue for games 2021-07-13 20:11:47 +03:00
fcf4d91564 Merge remote-tracking branch 'upstream/master' 2021-07-13 20:00:17 +03:00
38319871e6 Merge pull request #1225 from dannkunt/patch-1
Fix wrong type hint
2021-07-13 11:32:06 +03:00
2d0b092ea4 Fix wrong type hint
call.id gives int
2021-07-10 22:03:31 +03:00
060b8c61bb Merge remote-tracking branch 'upstream/master' 2021-07-09 10:50:53 +03:00
db2accc2f8 Merge pull request #1223 from Badiboy/master
Timeouts in making requests are rethought
2021-07-09 10:50:46 +03:00
798fda4c8a Merge remote-tracking branch 'upstream/master' 2021-07-09 10:50:03 +03:00
2578e48134 Timeouts in making requests are rethought 2021-07-09 10:42:56 +03:00
ac20216a7a Merge pull request #1222 from Badiboy/master
Preserve dict change in de_json routines
2021-07-08 13:43:09 +03:00
beb5a456eb Preserve dict change in Update 2021-07-08 09:35:48 +03:00
41faadd572 Merge pull request #1221 from AndydeCleyre/feature/mentioncolorcodebot
mention colorcodebot as a project using this library
2021-07-08 08:36:22 +03:00
a15016d7d9 mention colorcodebot as a project using this library 2021-07-07 13:00:32 -04:00
47dd84c441 Merge pull request #1216 from SwissCorePy/master
fixed bug
2021-07-01 20:04:37 +03:00
c7b360e982 fixed bug 2021-07-01 18:54:39 +02:00
09041b018f Merge pull request #1215 from SwissCorePy/master
Added the property `difference` to the class ChatMemberUpdated
2021-06-30 17:33:13 +03:00
3a4cf47def Merge branch 'master' of https://github.com/SwissCorePy/pyTelegramBotAPI 2021-06-30 14:16:54 +02:00
56e4f68a83 added the property difference to ChatMemberUpdated 2021-06-30 14:16:38 +02:00
484e7fccbd Merge pull request #1214 from SwissCorePy/master
new deprecated decorator
2021-06-30 15:01:46 +03:00
791d65e95a replaced old deprecated decorator 2021-06-30 13:47:39 +02:00
073d7fb6a7 Update util.py
whoops warn is not optional
2021-06-30 13:11:48 +02:00
a6668397e1 new deprecated decorator
added a new deprecated decorator to util
2021-06-30 13:08:05 +02:00
983d626d87 Merge pull request #1212 from Badiboy/master
Update file_name to visible_file_name in send_document
2021-06-29 13:31:25 +03:00
a4e73a05c6 Update file_name to visible_file_name in send_document 2021-06-29 13:30:01 +03:00
30e304ffb5 Merge pull request #1204 from floydya/file-name-patch
Allows to set visible document file_name on send.
2021-06-29 13:27:44 +03:00
430b34c7a2 Merge pull request #1210 from SwissCorePy/master
README update
2021-06-28 17:15:45 +03:00
b222416fd8 Update README.md 2021-06-28 15:44:49 +02:00
f8110cd046 Update README.md
* Added the new message_handlers
* Added some information about local Bot API Server
* Replaced the split_string with the smart_split function
2021-06-28 15:17:53 +02:00
6bc60f4aa9 Merge pull request #1208 from SwissCorePy/master
get_chat_member_count and ban_chat_member added.
get_chat_members_count and kick_chat_member are marked as deprecated.
2021-06-28 13:09:19 +03:00
b48a445e9f Update __init__.py
updated docstrings
2021-06-28 12:02:40 +02:00
0b383498eb addded logger info for deprecated funcs 2021-06-28 11:59:21 +02:00
2e3b4223a5 Merge pull request #1209 from Badiboy/master
Release 3.8.1 - bugfix
2021-06-28 12:41:38 +03:00
60bb63ab2b Release 3.8.1 - bugfix 2021-06-28 12:41:15 +03:00
0aa7a8a8f6 new 5.3 function names
added the new function names (the previous names are still working) from 5.3 and some other small changes
2021-06-28 09:31:06 +02:00
72ed7c1dde Merge pull request #1207 from Badiboy/master
Post-release fix for infinity_polling
2021-06-27 20:43:34 +03:00
a29c4af2ee Post-release fix for infinity_polling 2021-06-27 20:40:16 +03:00
8d8f234138 Merge pull request #1206 from MAIKS1900/master
2 of 3 Bot API 5.3 changes
2021-06-27 17:33:04 +03:00
491cc05a95 - Set BotCommandScope as abstract class.
- Docstrings from telegram API Scope types
2021-06-27 17:28:11 +03:00
b2c6077f4d Merge branch 'master' of https://github.com/MAIKS1900/pyTelegramBotAPI into master 2021-06-27 15:08:37 +03:00
fb290dc12d Merge pull request #1205 from Badiboy/master
Release version 3.8.0
2021-06-27 13:24:55 +03:00
c088fabe6c Release version 3.8.0 2021-06-27 13:09:08 +03:00
a791ff4e46 Add tests for file sending with name 2021-06-27 11:58:33 +03:00
e56f134a7c Add file_name support to send_document method 2021-06-27 11:38:45 +03:00
38c4c21030 Add file_name argument to send_data method 2021-06-27 11:37:27 +03:00
3e33b7f1cb Bot API 5.3 changes
- Personalized Commands for different chats
- Custom Placeholders of input field for ReplyKeyboardMarkup and ForceReply.
2021-06-26 14:36:14 +03:00
e381671645 Merge pull request #1201 from SwissCorePy/master
Added handlers for `my_chat_member` and `chat_member`.
Added aalowed_updates to polling functions.
2021-06-24 09:06:33 +03:00
ce991e9ac3 Update types.py
added the missing attributes `can_manage_chat` and `can_manage_voice_chats` to ChatMember class
2021-06-23 22:52:24 +02:00
3d5415433e Update __init__.py
Updated TeleBot doc string and added the missing functions to AsyncTeleBot
2021-06-23 22:51:17 +02:00
0bfefdf15d changed allowed_updates in util to update_types
i think its more clear name
2021-06-23 19:57:44 +02:00
506464e637 Update __init__.py
Added the parameter `allowed_updates` to polling and infinity_polling functions
2021-06-23 19:29:36 +02:00
4554cb969f Update __init__.py
added handlers for `my_chat_member` and `chat_member`
2021-06-23 16:10:48 +02:00
65cf841015 Update util.py
added `allowed_updates` list (used by `_init_._retrieve_all_updates` because `chat_member` is not requested by default)
2021-06-23 16:09:40 +02:00
0f0ce934dc Merge pull request #1199 from SwissCorePy/master
added InputInvoiceMessageContent and tgs_sticker support
2021-06-22 17:34:05 +03:00
bffbe764e5 Update tgs_sticker support
* Updated `create_new_sticker_set` and `add_sticker_to_set` functions
* Removed `create_new_animated_sticker_set` and `add_sticker_to_animated_sticker_set` functions
2021-06-22 15:57:34 +02:00
c00595e212 Update types.py
* Added Parameter `caption_entities` to `InputMedia` class
* Added Parameter `disable_content_type_detection` to `InputMediaDocument` class
2021-06-22 15:55:14 +02:00
b20f5b359b Merge pull request #1200 from pablodz/patch-1
Fix long string blocking version of python on github actions setup
2021-06-22 08:29:50 +03:00
558eef78b4 Fix long string blocking version of python on github actions setup 2021-06-21 17:27:35 -05:00
3f46ce3b7b added InputInvoiceMessageContent and tgs_sticker support
and some small changes
2021-06-21 19:59:39 +02:00
69e8edef19 Merge pull request #1198 from SwissCorePy/master
Added some missing features
2021-06-21 20:48:04 +03:00
d3369245c4 fixed wrong type hint 2021-06-21 17:49:03 +02:00
55e9f2095e Merge branch 'master' of https://github.com/eternnoir/pyTelegramBotAPI 2021-06-21 17:39:57 +02:00
7118613ef7 Added missing features
* added some missing features of TelegramBotAPI 4.6-5.2 to pyTelegramBotAPI
* added type hints to (almost) all public TeleBot functions
2021-06-21 17:39:13 +02:00
105d65d5ce Merge pull request #1197 from vishal2376/master
Add developer bot
2021-06-21 14:16:37 +03:00
f11bf08ba1 Update README.md 2021-06-21 16:30:17 +05:30
66598e39fe Change description of developer bot 2021-06-21 16:27:32 +05:30
4146b50384 Add developer bot 2021-06-21 13:16:22 +05:30
f62d642572 Merge pull request #1196 from leonheess/patch-1
Add Anti-Tracking Bot
2021-06-20 19:33:50 +03:00
18f1fd42b0 Add Anti-Tracking Bot 2021-06-20 13:14:55 +02:00
07d198aebe Merge pull request #1195 from SwissCorePy/master
Added class ChatMemberUpdated
2021-06-19 22:18:50 +03:00
0370a9f277 Added class ChatMemberUpdated
* Added class `ChatMemberUpdated` to types
* Simplified `de_json` functions in `WebhookInfo` and `Update` classes (for overall more consistent code)
* changed `options_ids` to ´option_id` in class `PollAnswer`
* Added test for `ChatMemberUpdated` class in `test_types.py` and added the fields `my_chat_member` and `chat_member` to the `Update` class and its tests
2021-06-19 20:13:53 +02:00
22d3ac027a Merge pull request #1194 from SwissCorePy/master
Minor updates to the https://github.com/eternnoir/pyTelegramBotAPI/pull/1191
2021-06-19 19:25:04 +03:00
795f7fff7f Some small changes
* Fixed type warnings in some editors by changing `var: Type = None` to `var: Union[Type, None] = None`
* changed some args from `obj['arg']` to `obj.get('arg')` if arg is optional
* better PEP-8 compliance for less weak warnings
* added tests for the new type `ChatInviteLink`
2021-06-19 17:59:55 +02:00
ab6d40a072 Merge pull request #1193 from Badiboy/master
Raise exception if no token passed
2021-06-19 15:10:32 +03:00
d26923e167 Raise exception if no token passed 2021-06-19 15:09:52 +03:00
05aff236c1 Merge pull request #1191 from SwissCorePy/master
Huge update with type checking and some new properties.

Note: should be presisely tested before publishing.
2021-06-19 15:00:12 +03:00
a9ae070256 Update types.py 2021-06-18 22:37:31 +02:00
63fe6e01d1 Fixed the errors from my last PRs
I testet all using pytest and python versions 3.6-3.9 on macOS
2021-06-18 22:35:49 +02:00
bbafdd1c1d Some Updates
> Added lot of type hints to types.py
> Added some new fields from TelegramBotAPI to pyTelegramBotAPI
> fixed `circular import error in util.py
> Added functions `log_out` and `close` to __init__.py and apihelper.py
> And some more small changes
2021-06-17 20:28:53 +02:00
fe9df2df8c Merge pull request #1186 from AREEG94FAHAD/master
Add to translator bot
2021-06-12 21:13:41 +03:00
b0b8623dce Merge pull request #1 from AREEG94FAHAD/Cryptocurrency
Update README.md
2021-06-12 19:02:06 +03:00
a01e59951a Update README.md 2021-06-12 19:01:42 +03:00
d5c202abbd Update README.md 2021-06-12 18:19:18 +03:00
81299ff613 Update README.md 2021-06-12 18:18:51 +03:00
25bac68309 Update README.md 2021-06-12 18:18:16 +03:00
a05324bdad Merge pull request #1181 from pablodz/master
Github Actions: setup for 3.6+ pypy3.6+
2021-06-09 17:29:57 +03:00
74c4ab2f04 Merge pull request #1183 from SwissCorePy/master
Fixed a bug in `user_link`
2021-06-09 17:28:13 +03:00
ab05cb0045 Fixed a bug in user_link
`user_link` returned an empty string if `include_id` was set to False
2021-06-09 16:20:42 +02:00
709eb8cf45 Github Actions: setup for 3.6+ pypy3.6+ 2021-06-06 14:30:55 -05:00
643cdeceee Merge pull request #1179 from Badiboy/master
Fix special case when content_type is None
2021-06-04 12:29:05 +03:00
2add34c702 Fix special case when content_type is None 2021-06-04 12:28:33 +03:00
877397a46b Merge pull request #1178 from Badiboy/master
Partial rollback for previous update
2021-06-04 12:12:26 +03:00
afbc67795a Partial rollback for previous update 2021-06-04 12:11:37 +03:00
da5dc20b3a Merge pull request #1176 from SwissCorePy/master
Added some functions and type hints
2021-06-03 23:45:21 +03:00
ed5e5e5077 Update util.py
- Removed function `unix_time`
- Added function `escape`
- Added function `user_link`
- Added function `quick_markup`
- Added some type hints
2021-06-03 19:51:33 +02:00
9a6ddce8df Added the function unix_time 2021-06-03 19:06:53 +02:00
db8478d0a4 Merge pull request #1174 from SwissCorePy/master
Add `smart_split` function to utils.py
2021-06-03 19:55:44 +03:00
20030f47af Update util.py
Added the function `smart_split` to split text into meaningful parts.
2021-06-03 18:51:32 +02:00
f7cf1965cb Merge pull request #1168 from anvarjamgirov/patch-1
Bug fixed on set_game_score
2021-06-01 08:30:42 +03:00
aea067f789 Bug fixed on set_game_score
fixed wrong ordered argument error on calling apihelper.set_game_score method in set_game_score
2021-06-01 08:39:09 +05:00
e2c20c1e55 Merge pull request #1167 from zora89/master
typo corrected.
2021-05-25 23:56:01 +03:00
1209281787 type corrected. 2021-05-26 02:17:49 +05:30
742f67c85b Merge pull request #1163 from yehwankim23/patch-1
Fix typo
2021-05-20 12:07:34 +03:00
e22fcbe3c0 Fix typo 2021-05-20 18:01:10 +09:00
d3998dfadb Merge pull request #1161 from yarreg/feature/invite-link-api
Create_chat_invite_link, edit_chat_invite_link, revoke_chat_invite_link methods
2021-05-19 11:30:06 +03:00
ff54f194ad Added: create_chat_invite_link, edit_chat_invite_link, revoke_chat_invite_link methods 2021-05-19 11:22:40 +03:00
f6b967421e Merge pull request #1160 from Badiboy/master
Update version.py
2021-05-15 20:30:27 +03:00
59559199d5 Update version.py 2021-05-15 20:29:58 +03:00
98784c811e Merge pull request #1159 from Badiboy/master
Fix release 3.7.8u1 (update was inconsistent, sorry)
2021-05-15 20:28:51 +03:00
26e5f3d3a8 Fix release 3.7.8u1 2021-05-15 20:27:52 +03:00
fe1f99abdf Merge pull request #1158 from Badiboy/master
send_poll fix of fix
2021-05-15 20:09:49 +03:00
7540a26fb9 send_poll fix of fix
Previous update was inconsistent, sorry.
2021-05-15 20:08:51 +03:00
10d0ff2c06 Merge pull request #1157 from Badiboy/master
Release 3.7.8
2021-05-15 11:36:00 +03:00
90de2e4ad9 Release 3.7.8
Regular release with minor updates
2021-05-15 11:35:13 +03:00
d3c2ffd422 Merge pull request #1155 from Badiboy/master
send_poll fix with PollOptions
2021-05-15 11:31:02 +03:00
53c98328c1 send_poll fix with PollOptions
Now send_poll correctly operates with PollOptions passed as array of PollOption.
2021-05-12 00:26:33 +03:00
3d26a0ce0d Merge pull request #1154 from Badiboy/master
Change message handler filtering order
2021-05-11 23:27:54 +03:00
73fb18c193 Change message handler filtering order
Now content_type is checked first.
2021-05-11 23:26:22 +03:00
1ba595daa0 Merge pull request #1153 from hemantapkh/patch-1
Add Torrent Hunt bot in README
2021-05-11 09:23:59 +03:00
47cab4d63e Fix typo 2021-05-11 07:58:19 +05:45
4a25675007 Add Torrent Hunt bot in README 2021-05-11 07:51:13 +05:45
c437b40d58 Merge pull request #1140 from eternnoir/dependabot/pip/py-1.10.0
Bump py from 1.4.29 to 1.10.0
2021-04-20 22:00:39 +03:00
b7a18bf0d9 Bump py from 1.4.29 to 1.10.0
Bumps [py](https://github.com/pytest-dev/py) from 1.4.29 to 1.10.0.
- [Release notes](https://github.com/pytest-dev/py/releases)
- [Changelog](https://github.com/pytest-dev/py/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/py/compare/1.4.29...1.10.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-20 17:03:50 +00:00
bc3d5a46b7 Merge pull request #1138 from Badiboy/master
Python 3.5 end-of-life
2021-04-19 18:46:53 +03:00
990bb827be Python 3.5 end-of-life 2021-04-19 18:45:49 +03:00
3ecb84bd94 Merge pull request #1137 from FosterToster/master
middleware handlers exception handling
2021-04-19 18:42:24 +03:00
2565094897 fixed overwriting exception args 2021-04-19 22:20:42 +07:00
855b838e91 more explict process_middleware exceptions suppressing 2021-04-18 22:41:28 +07:00
042d8c17da suppress_middleware_excepions configuration. False by default. 2021-04-18 22:31:24 +07:00
a39fb14726 middleware handlers exception handling 2021-04-18 19:56:52 +07:00
888c7a6b0d Merge pull request #1126 from David256/feature-new-property-fullname
Change fstrings to string formatting
2021-04-02 01:41:48 +03:00
2f69917a82 Change fstrings to string formatting 2021-04-01 16:52:12 -05:00
efa35ba71c Merge pull request #1125 from David256/feature-new-property-fullname
New property full_name
2021-04-02 00:05:29 +03:00
6c90da793e New property full_name 2021-04-01 14:56:08 -05:00
4024490249 Merge pull request #1121 from Badiboy/master
Minor release
Heroku example update
2021-03-28 11:57:49 +03:00
209d9b27b4 Minor release 2021-03-28 11:57:05 +03:00
96e0be8942 Heroku example update 2021-03-28 11:54:46 +03:00
87bce0bce1 Merge pull request #1113 from barbax7/master
Added Price Tracker bot
2021-03-18 17:43:43 +03:00
f23059d7ec Added Price Tracker bot 2021-03-18 08:38:47 +01:00
cc08fe32c6 Merge pull request #1107 from MasterGroosha/patch-1
Removed my bot from README
2021-03-09 10:35:06 +03:00
07e93f95a1 Removed my bot from list
The link is now dead, and so is that bot
2021-03-09 02:05:44 +03:00
a10e8afa5c Merge pull request #1096 from anvaari/master
Add my bot to Readme.md
2021-02-16 13:25:07 +03:00
b39244f827 Add my bot to Readme.md 2021-02-16 13:41:56 +03:30
af4d986a13 Merge pull request #1090 from Badiboy/master
Custom logging level for infinity_polling
2021-02-05 00:43:22 +03:00
8790f26e68 Custom logging level for infinity_polling 2021-01-30 14:41:19 +03:00
f01412a996 Merge pull request #1086 from dexpiper/patch-1
README list of bots update
2021-01-22 16:56:02 +03:00
20d0ab229f README list of bots update
Add another bot to the list below
2021-01-21 17:19:54 +03:00
2dec4f1ffc Merge pull request #1083 from ModischFabrications/patch-1
Add MineGramBot to readme
2021-01-20 13:31:05 +03:00
a7d1dbf0e9 add MineGramBot 2021-01-20 11:04:55 +01:00
eace25d9d2 Merge pull request #1082 from Badiboy/master
Minor update to copyMessage
2021-01-19 01:28:16 +03:00
fdf2838669 Minor update to copyMessage 2021-01-19 01:27:39 +03:00
74fb8258b6 Merge pull request #1067 from Aazerra/copyMessage_method
Added copyMessage method
2021-01-19 01:16:09 +03:00
cc299fe4da Merge pull request #1081 from ModischFabrications/patch-1
Extend readme with more usage hints
2021-01-18 02:26:02 +03:00
cd31c8db5c fix example 2021-01-17 23:47:03 +01:00
6d7116d521 document SESSION_TIME_TO_LIVE 2021-01-17 23:45:23 +01:00
f93916372e document edit_message_text in readme 2021-01-17 23:34:54 +01:00
80c9e17fd4 add apihelper.ENABLE_MIDDLEWARE = True to readme 2021-01-17 23:22:45 +01:00
003a92f466 Merge pull request #1080 from Badiboy/master
Release v.3.7.6
2021-01-18 01:02:45 +03:00
d57aa04bfb Release v.3.7.6 2021-01-18 01:02:19 +03:00
9c2d279806 Merge pull request #1078 from ModischFabrications/patch-1
Hide token from debug logs
2021-01-17 12:21:42 +03:00
3109e35bb4 show bot id 2021-01-17 01:26:38 +01:00
ea51b1e95e hide token from debug logs
prevent leaks of the bot token by hiding it from the log
2021-01-17 01:06:47 +01:00
3799a1e99a Merge pull request #1077 from Badiboy/master
Added short live sessions
2021-01-17 00:46:01 +03:00
ec8714ad3a Short live sessions u1 2021-01-17 00:43:52 +03:00
bc54a5379c Added short live sessions 2021-01-16 23:50:25 +03:00
a7587057bf Merge pull request #1076 from Badiboy/master
Polling timeout fix
2021-01-16 02:15:26 +03:00
e9ba2fd8bb Polling timeout fix 2021-01-16 02:14:29 +03:00
8203fa588f Merge pull request #1074 from Badiboy/master
Version update to previous commit
2021-01-14 15:49:01 +03:00
2e5250ec98 Version update to previous commit 2021-01-14 15:48:30 +03:00
1f910745f1 Merge pull request #1073 from Badiboy/master
Fix restrict_chat_member until_date bug
2021-01-14 15:47:21 +03:00
f56da17741 Fix restrict_chat_member until_date bug 2021-01-14 15:45:47 +03:00
a0d86977b0 Merge pull request #1072 from Badiboy/master
Infinity polling fall down fixed
2021-01-14 03:57:00 +03:00
82838e1d26 Infinity polling fall down fixed 2021-01-14 03:44:37 +03:00
bb8bc7672a Merge pull request #1070 from dgarcoe/patch-1
Update README.md
2021-01-13 20:03:10 +03:00
6e3e159109 Update README.md
I included my bot in the README. Thanks for the library!
2021-01-13 17:55:08 +01:00
b561e35330 Update __init__.py 2021-01-12 11:19:57 +03:30
b684c4f60d Fix Things on copyMessage 2021-01-12 11:17:53 +03:30
58281f0a10 Added copyMessage method 2021-01-11 02:50:17 +03:30
87574a7613 Merge pull request #1066 from Badiboy/master
drop_pending_updates in set_webhook
2021-01-09 21:23:55 +03:00
52ebb5a1a7 drop_pending_updates in set_webhook 2021-01-09 21:22:49 +03:00
da9ee5ffba Merge pull request #1065 from Badiboy/master
Release version  3.7.5
2021-01-07 20:47:12 +03:00
0900acfae9 Release version 3.7.5 2021-01-07 20:46:50 +03:00
c6cf615722 Merge pull request #1062 from Badiboy/master
Added timeout to xxx_webhook
2021-01-07 02:38:26 +03:00
5dc008a762 Added timeout to xxx_webhook 2021-01-07 00:13:44 +03:00
bbcd7aa9db Merge pull request #1060 from TarasKindrat/master
Modify RedisHandlerBackend, add argument "password=None" to __init__()
2021-01-06 15:06:24 +03:00
51effdd9a1 Merge pull request #1061 from barbax7/patch-2
Added bot @donamazonbot to the list
2021-01-06 15:05:37 +03:00
0126ba82a5 Added bot @donamazonbot to the list 2021-01-05 17:31:18 +01:00
6b0484b9db Modify RedisHandlerBackend, add argument "password=None" to __init__()
With argument "password=None" in method __init__(), and argument "password" in "self.redis = Redis(host, port, db, password)", will be able to use Redis with password protection, if password is set .
2021-01-05 13:06:14 +02:00
eab36a99e9 Update README.md 2021-01-01 23:14:00 +08:00
28357c8c33 Merge pull request #1056 from Badiboy/master
Bot API update
2020-12-29 19:27:06 +03:00
6559f431b7 Bot API update
Bot API conformance up to 4.4

Added webhook parameters from 5.0
2020-12-29 19:24:41 +03:00
b5d054cf5f Merge pull request #1054 from timgates42/bugfix_typo_performance
docs: fix simple typo, perfomance -> performance
2020-12-25 01:52:17 +03:00
93b86307d9 docs: fix simple typo, perfomance -> performance
There is a small typo in examples/webhook_examples/README.md.

Should read `performance` rather than `perfomance`.
2020-12-25 09:47:40 +11:00
f62d72e2a1 Merge pull request #1053 from Badiboy/master
Avoid dead threads in treaded polling
2020-12-25 00:03:24 +03:00
c4e624d999 Avoid dead threads in treaded polling 2020-12-24 23:55:12 +03:00
fcb3d9b1b3 Merge pull request #1052 from Badiboy/master
Exception if middleware is used but not enabled
2020-12-24 19:57:25 +03:00
2534dc5925 Exception if middleware is used but not enabled. 2020-12-24 19:55:24 +03:00
ded0d257fc Merge pull request #1050 from twistfire92/master
fix restrict_chat_member method
2020-12-22 23:05:43 +03:00
96686e5221 fix restrict_chat_member method 2020-12-22 21:38:38 +03:00
b522053e27 Merge pull request #1043 from vixfwis/master
Add webhook example for Twisted
2020-12-17 16:49:26 +03:00
4e61bc3a8b add short description to example and readme files 2020-12-17 15:34:36 +03:00
487ede7c88 Merge pull request #1046 from Badiboy/master
Fix unban_chat_member in async
2020-12-16 01:58:31 +03:00
4658d2b8da Fix unban_chat_member in async 2020-12-16 01:57:30 +03:00
75a18e5869 add webhook example for Twisted framework 2020-12-15 15:02:41 +03:00
fab2b2d223 Merge pull request #1035 from Badiboy/master
parse_mode = ""
2020-12-09 11:23:09 +03:00
65c3ca58da Update __init__.py
Allow parse_mode = "" to disable default parse mode.
2020-12-09 01:41:07 +03:00
a4d0b685b5 Merge pull request #1026 from Badiboy/master
Bot API 5.0 pinning-unpinning logic post-fix.
2020-11-29 16:11:46 +03:00
6cc80f25d7 Bot API 5.0 pinning-unpinning logic post-fix. 2020-11-29 15:33:39 +03:00
0418818629 Merge pull request #1025 from alexmechanic/master
Bot API 5.0 pinning-unpinning logic update
2020-11-29 15:28:43 +03:00
b9898bbdda Fix 0a2216a22b #2
+ message_id arg of unpin_chat_message() passing to the helper
- removed passing arg to unpin_all_chat_messages()
2020-11-29 15:21:59 +03:00
00c9351f83 Hotfix 0a2216a22b
* message_id made optional as API declares
2020-11-29 15:12:14 +03:00
0a2216a22b Bot API 5.0 pinning-unpinning logic update
+ add unpin_all_chat_messages() (former unpin_chat_message())
* update unpin_chat_message() (add message_id arg)
2020-11-29 14:47:53 +03:00
438cfe4dbd Merge pull request #1022 from Badiboy/master
Version 3.7.4 release
2020-11-20 23:50:39 +03:00
640f398262 Version 3.7.4 release 2020-11-20 23:49:55 +03:00
a9db217c64 Merge pull request #1020 from Badiboy/master
added only_if_banned to unban_chat_member
2020-11-20 15:05:41 +03:00
5824d47590 added only_if_banned to unban_chat_member 2020-11-18 02:22:52 +03:00
0da192aec7 Merge pull request #1014 from Badiboy/master
set_webhook bugfinx
2020-11-11 01:02:21 +03:00
bd27645965 set_webhook bugfinx
set_webhook does not reset allowed_updates for empty list (to default)
2020-11-11 00:32:34 +03:00
2c15cd0996 Merge pull request #1012 from Badiboy/master
Long polling timeouts update
2020-11-07 16:51:10 +03:00
00d125a298 long_polling_timeout update 3 2020-11-07 14:59:45 +03:00
a548374a4d long_polling_timeout update 2 2020-11-07 14:43:17 +03:00
03e1aef70e long_polling_timeout update 1 2020-11-07 14:02:11 +03:00
ece7ca97e0 Merge pull request #1011 from Badiboy/master
Long polling updates and combo content types
2020-11-07 13:02:22 +03:00
7a3fd30f6a Long polling updates and combo content types 2020-11-07 12:52:51 +03:00
1d99cc224f Merge pull request #1005 from Badiboy/master
Animation content_type
2020-11-03 23:26:53 +03:00
fa3ca84d24 Animation content_type
"When you send gif telegram gives you animation and document at same time in update and when you parse that first if is animation and second is document because of this the content_type set document not animation"
2020-11-03 17:46:19 +03:00
42e6d84f13 Merge pull request #1004 from diegop384/patch-1
Update README.md
2020-11-03 17:36:04 +03:00
27461c03af Update README.md
I added my bot
2020-11-03 09:28:31 -05:00
3be51390b1 Merge pull request #997 from Mrsqd/patch-1
Added Frcstbot description
2020-10-30 00:42:04 +03:00
afa88304d7 Added Frcstbot
I've made a weather forecast bot using your API. Can you approve my request to add it, please?
2020-10-29 02:09:47 +03:00
82e79b6ac6 Merge pull request #995 from pinguluk/patch-1
Update README.md
2020-10-28 14:16:03 +03:00
746c71665e Update README.md
linked example/webhook_examples to the directory
2020-10-28 12:31:57 +02:00
37c09406d0 Merge pull request #989 from andvch/patch-1
Fix broken text_mention html formatting
2020-10-15 11:57:38 +03:00
36a3ce62c4 Fix broken text_mention html formatting 2020-10-14 12:06:49 +03:00
6dc8173176 Merge pull request #977 from Badiboy/master
Previous commit bugfix
2020-09-22 01:46:51 +03:00
00c2e9b51c Piece death fix 2020-09-22 01:41:51 +03:00
29711e2425 Merge remote-tracking branch 'upstream/master' 2020-09-22 01:34:55 +03:00
75a5dd1492 Minor bugfix 2020-09-22 01:34:49 +03:00
3ae145f206 Update README.md 2020-09-10 16:22:50 +08:00
5fda52cf5d Merge pull request #970 from meoww-bot/master
UPG: Added the field reply_markup to the Message object
2020-09-07 13:09:46 +03:00
9ab906e60c fix: simplify code
json.loads(button.to_json()) equals to button.to_dict()
2020-09-02 18:09:14 +08:00
698b4371e6 test: Add tests for InlineKeyboardMarkup and ...
Add tests for InlineKeyboardMarkup and InlineKeyboardButton
2020-09-02 10:33:32 +08:00
a803edd09b fix: button in markup should be obj, not json text 2020-09-02 09:25:23 +08:00
32a9e65ecc fix: reply_markup does not change content_type 2020-09-02 09:12:49 +08:00
decad450d0 feat: make InlineKeyboardMarkup JsonDeserializable
feat: make InlineKeyboardMarkup JsonDeserializable, add de_json func to InlineKeyboardMarkup object
2020-09-01 18:13:22 +08:00
630a9a5b2c feat: make InlineKeyboardButton JsonDeserializable
feat: make InlineKeyboardButton JsonDeserializable, add de_json func to InlineKeyboardButton Object
2020-09-01 18:07:45 +08:00
cdae65116b feat: make LoginUrl JsonDeserializable
feat: make LoginUrl JsonDeserializable, add de_json func
2020-09-01 18:03:21 +08:00
6832c33733 feat: Added the field reply_markup to the Message
Added the field `reply_markup` to the Message object
2020-08-31 12:00:56 +00:00
d15cb16bef Merge pull request #969 from ArtemFrantsiian/patch-1
Fix an error with the is_pil_image function
2020-08-29 22:04:36 +03:00
81100f249c Fix an error with the is_pil_image function
When I've tried to send_photo as shown in detailed_example, I got an error: "AttributeError: module 'PIL' has no attribute 'Image'". 
This error was described well here: https://stackoverflow.com/a/11911536/9092263. So in accordance to prescriptions, I've made changes and It works fine for me.

Steps to reproduce:
1. initiate bot via TeleBot constructor
2. call function bot.send_photo(call.message.chat.id, open("some_image.jpg", "rb"))

P.S.
Error Environment: 
- python==3.8.5
- pyTelegramBotAPI==3.7.3
- PIL==7.2.0
2020-08-29 21:57:41 +03:00
79ff9191f3 Merge pull request #967 from meoww-bot/patch-1
Added the field `file_unique_id` (Bot API 4.5)
2020-08-29 11:18:00 +03:00
bdfb793e34 test: Added file_unique_id from Bot API 4.5 2020-08-29 12:07:38 +08:00
e811163b5f UPG: Added the field file_unique_id
Added the field file_unique_id to the objects Animation, Audio, Document, PassportFile, PhotoSize, Sticker, Video, VideoNote, Voice, File and the fields small_file_unique_id and big_file_unique_id to the object ChatPhoto. (Bot API 4.5)
2020-08-29 04:29:02 +08:00
1eb9651894 Merge pull request #963 from Badiboy/master
Minor readme update
2020-08-26 00:53:12 +03:00
309e55845c Minor readme update 2020-08-26 00:51:55 +03:00
2bc5c1a500 Merge pull request #960 from CrafterKolyan/patch-1
Add last_update_id parameter for constructor
2020-08-25 21:58:33 +03:00
7acad2d825 Merge pull request #958 from Badiboy/master
Bot API support checked/updated up to 4.2
2020-08-25 21:49:40 +03:00
5120650774 Move parameter to the end of list 2020-08-25 21:45:30 +03:00
c13f9a7f98 Add last_update_id parameter for constructor 2020-08-25 21:26:28 +03:00
bab9b4077d Bot API support checked/updated up to 4.2 2020-08-25 18:18:51 +03:00
47b9c1d3fb Merge pull request #957 from Badiboy/master
Empty list optimization, Py2 arteacts removed
2020-08-25 16:46:28 +03:00
06ed637f2f Merge remote-tracking branch 'upstream/master' 2020-08-25 16:24:07 +03:00
7bf432170e Merge pull request #956 from Pablo-Davila/master
Append bots to list
2020-08-25 16:23:52 +03:00
8cd18945c5 Append bots to list
TasksListsBot
MyElizaPsychologistBot
2020-08-25 15:45:08 +02:00
48b53f6a8e Update version.X 2020-08-24 21:36:27 +08:00
cdd48c7aed Empty list optimization, Py2 arteacts removed,
Empty list optimization: None instead of [].

Py2 arteacts removed: no more six moudle used.
2020-08-24 16:02:35 +03:00
513a85cad9 Merge remote-tracking branch 'upstream/master' 2020-08-24 13:00:30 +03:00
c1c84a588d Merge pull request #955 from fgallaire/master
Fix 'NoneType' object assignment error from #892 and #954
2020-08-22 18:32:25 +03:00
5e19965b0c Fix 'NoneType' object assignment error from #892 and #954 2020-08-22 16:11:52 +02:00
17f48916ad Merge remote-tracking branch 'upstream/master' 2020-08-21 17:40:56 +03:00
5b70980bda Resolve conflicts 2020-08-21 17:38:54 +03:00
73487f96c4 Custom exception handler for poll mode
Initial beta of custom exception handler for poll mode.

Use ExceptionHandler class and bot.exception_handler to proceed unhandled exceptions in poll mode.
2020-08-21 17:36:08 +03:00
818905de32 Merge pull request #954 from rfoxxxy/master
Added missing thumb parameters to send_document, send_animation and send_video_note
Implemented getting the runtime version of pyTelegramBotAPI
Fixed docstring for send_video_note function
2020-08-21 17:33:22 +03:00
cab33ad0d9 fixed thumb processing 2020-08-21 14:09:38 +03:00
9ca3c78c84 back version to 3.7.2 2020-08-21 11:22:24 +03:00
0ab4046a4f Create version.py 2020-08-21 11:09:53 +03:00
8b50dc488b added missing thumb params and more 2020-08-21 11:09:43 +03:00
83df269730 Merge pull request #953 from Badiboy/master
Two None checks
2020-08-20 00:00:57 +03:00
18eb8eb605 Two None checks 2020-08-19 23:57:48 +03:00
19aaf83d88 Merge pull request #950 from BLUE-DEVIL1134/master
Update README.md
2020-08-17 11:48:59 +03:00
3b57c288b4 Update README.md 2020-08-17 14:08:20 +05:30
8f1c34db76 Merge pull request #947 from BLUE-DEVIL1134/master
Update README.md
2020-08-14 22:07:47 +08:00
2aaff09c39 Update README.md 2020-08-14 11:38:57 +05:30
1cd36253f0 Update README.md 2020-08-14 11:36:04 +05:30
484c3a4c48 Update README.md 2020-08-14 10:50:56 +05:30
5347a068e0 Merge pull request #944 from barbax7/patch-1
Update README.md
2020-08-13 18:25:23 +03:00
52511fce48 Update README.md
Added my bot to the list.
2020-08-13 12:14:57 +02:00
507d524215 Merge pull request #939 from mrpes/patch-6
Keyboard bugfix
2020-08-04 22:03:00 +03:00
ec79d1dc1e Keyboard bugfix 2020-08-04 23:45:33 +05:00
31e40d155b Merge pull request #938 from Badiboy/master
CopyPaste bugfix
2020-08-04 18:29:31 +03:00
c6f51f6c55 CopyPaste bugfix 2020-08-04 18:28:35 +03:00
dc07cacc7f Merge pull request #935 from mrpes/patch-4
Exceptions classes redesign followup
2020-08-04 18:25:31 +03:00
ce6a21cd09 Merge branch 'master' into patch-4 2020-08-04 19:49:55 +05:00
58c4010155 Merge pull request #937 from Badiboy/master
Bugfix and DISABLE_KEYLEN_ERROR
2020-08-04 12:40:32 +03:00
a5fd407eb6 Bugfix and DISABLE_KEYLEN_ERROR
Bugfix and DISABLE_KEYLEN_ERROR to supress keyboard length errors.
2020-08-04 12:29:56 +03:00
1bb98483c2 Update apihelper.py 2020-08-04 05:34:13 +05:00
67fdb2f52e Merge pull request #934 from Badiboy/master
Minor keyboard update followup
2020-08-03 11:37:09 +03:00
c17a2379ba Exceptions classes redesign followup 2020-08-03 06:39:12 +05:00
cc36207992 Minor keyboard update followup 2020-08-02 18:58:22 +03:00
e987e40ee7 Merge pull request #930 from mrpes/patch-5
Minor keyboard code redisign
2020-08-02 18:49:32 +03:00
1ba093cb02 Change logger level to warning 2020-08-02 20:30:58 +05:00
4e5fb59fc0 Replace exceptions with warnings
Also further PIL support added
2020-08-02 20:20:33 +05:00
317a490cf0 Type checking moved to utils 2020-08-01 01:30:38 +05:00
5823ca5613 Minor keyboard code redesign 2020-08-01 01:28:56 +05:00
9a3f370dce Merge pull request #929 from mrpes/patch-3
Support for sending PIL images in sendPhoto / sendChatPhoto as photo argument.
2020-07-31 11:06:31 +03:00
97aa9637cb Update apihelper.py 2020-07-31 10:45:58 +05:00
0ab908705b Support for PIL images as photo argument
Added autoconversion of PIL image to file-like object. PIL module is optional
2020-07-31 10:39:04 +05:00
88e0f1337b Merge pull request #928 from mrpes/patch-2
Exception classes redesign: additional Exception subclasses added
2020-07-31 01:37:32 +03:00
67536d4eec Fixing backward compatibility issue
Just realized that renaming ApiException to BaseApiException will cause backward compatibility issue
2020-07-31 03:30:03 +05:00
a14424704e Exception classes redesign
Replacing 1 exception class with 3 more specific classes: 
HTTP Exception (server returned http code != 200), 
Invalid JSON Exception (server returned invalid json),
Telegram Expection (telegram returned ok != true)

All 3 classes extend BaseApiException so we can handle all API exceptions at the same time
2020-07-31 03:10:34 +05:00
b790e4e6ba Merge pull request #927 from mrpes/patch-1
Optional retry on requests error
2020-07-30 11:14:51 +03:00
0ac64469b0 Retry on requests error
Added RETRY_ON_ERROR var. If its value is true, we'll try to get proper result MAX_RETRIES times, with RETRY_TIMEOUT delay between requests. Last request will be called outside of the try block, so it will throw an exception on failure

P.S.
I'm actually not sure if there are better ways to solve this problem, but this was my way of solving it
2020-07-30 09:34:51 +05:00
ce3c91b619 Merge pull request #919 from Badiboy/master
Minor updates in code
2020-07-21 01:27:32 +03:00
dbe9ce49df Minor updates in code 2020-07-21 01:20:01 +03:00
48e48610f3 Merge pull request #918 from daveusa31/master
Documented the default parse_mode installation
2020-07-18 23:01:25 +03:00
d7aaccef63 Merge pull request #917 from EskiSlav/master
Added strike and underline entities to parse to html
2020-07-18 21:19:47 +03:00
a02f499a20 Documented the default parse_mode installation 2020-07-18 19:02:07 +03:00
c533a52e39 Restored necessary comment 2020-07-18 00:25:00 +03:00
b50eb1bafb Added nested entities from Bot API 4.5 2020-07-17 13:43:45 +03:00
40e19e5af1 Merge pull request #915 from zeph1997/editreadme
Added JoinGroup Silencer Bot into the "Bots using this API" in README
2020-07-16 14:22:45 +03:00
bc5d9c8d69 Update README.md 2020-07-16 19:09:37 +08:00
6049de4356 Update README.md 2020-07-16 19:07:39 +08:00
b38ceaaec8 Merge pull request #913 from Aragroth/master
Added ability to specify params of width and height for video
2020-07-11 22:30:53 +03:00
7c94eee3a2 Update apihelper.py 2020-07-11 20:09:48 +03:00
00798df0c0 Merge pull request #909 from iPurya/patch-1
Fix Sticker tests
2020-07-07 09:17:01 +03:00
d2d7cc39be Update test_types.py 2020-07-07 03:39:00 +04:30
d74f47e16c Merge pull request #908 from iPurya/patch-2
Added field file_unique_id to Sticker.
2020-07-07 01:31:08 +03:00
d5e9f73821 Update test_types.py
tests updated for pull request #908.
2020-07-07 02:38:06 +04:30
49398f5c61 Update types.py
Sending stickers everytime have different file_id, so for detecting special stickers we need a unique parameter.
2020-07-07 01:31:33 +04:30
f42ec4fe0d Bump version. 2020-07-06 00:37:17 +08:00
e9f925e14c Merge pull request #906 from daveusa31/master
Added ability to set default parse_mode in main TeleBot class.
2020-07-04 22:29:32 +03:00
0304e6507f Append default parse_mode 2020-07-04 21:07:42 +03:00
0f387db8d2 Fix tabs 2020-07-04 20:45:48 +03:00
30664f396a Merge pull request #904 from timbyxty/master
Added NST bot to the bot list
2020-07-04 00:17:43 +03:00
cdffeba829 added NST 2020-07-03 22:05:47 +05:00
f4d978cd98 Update apihelper.py 2020-07-02 17:51:34 +03:00
f83f69ed50 Update apihelper.py 2020-07-02 17:50:14 +03:00
a69a358ebd Update __init__.py 2020-07-02 17:47:38 +03:00
4afde9f557 Update apihelper.py 2020-07-02 17:46:41 +03:00
8e82d1c462 Merge pull request #902 from 0xnu/patch-1
Update README.md
2020-07-02 16:08:22 +03:00
b5a4276282 Update README.md
Link to Sports bot added.
2020-07-02 13:27:51 +01:00
d43292e42b Merge pull request #892 from Otxoto/Otxoto-patch-2
Added thumbnail support for send_audio and send_video
2020-06-24 19:10:15 +03:00
99de5490a0 Added thumb parameter to send_video 2020-06-23 20:17:21 +02:00
53ccef5e5e added thumb parameter to send_video 2020-06-23 20:14:52 +02:00
29b432e65a Added thumb to send_audio 2020-06-23 20:12:46 +02:00
4f4c0891d9 Added thumb support to send_audio 2020-06-23 20:10:12 +02:00
03b1531bd7 Merge pull request #890 from Otxoto/master
Update User type
Added:
can_join_groups
can_read_all_group_messages
supports_inline_queries
2020-06-22 23:14:45 +03:00
ab496f995e Merge pull request #1 from Otxoto/Otxoto-patch-1
Complete User Class
2020-06-22 13:18:42 +02:00
44872ce87d Complete User Class
Added following fields:
can_join_groups
can_read_all_group_messages
supports_inline_queries
2020-06-22 13:18:13 +02:00
c24d1e2d0b Update README.md 2020-06-07 02:50:30 +08:00
38694a9173 Merge pull request #865 from Badiboy/master
Update test_telebot.py
2020-05-29 12:43:24 +03:00
1494946d02 Update test_telebot.py
Build fix.
2020-05-29 12:37:23 +03:00
5facf7de92 Merge pull request #808 from pikss86/master
Add possibility to create and use custom session, for examle - torpy
2020-05-29 12:17:58 +03:00
f7008d4d99 Merge pull request #856 from Badiboy/master
send_chat_permissions fix
2020-05-20 12:03:05 +03:00
32dc03ec44 send_chat_permissions fix 2020-05-20 11:57:41 +03:00
dbff7cbb3e Merge pull request #852 from olegshek/keyboard_button_poll_type
Keyboard button poll type
2020-05-18 11:23:02 +03:00
27e2cbc7ea Remove unnecessary test 2020-05-18 12:22:26 +05:00
592dcbfedf Add PollAnswer type;
Add poll_answer_handler
2020-05-18 12:05:30 +05:00
03b02561a5 Add request_poll attribute to KeyboardButton;
Add KeyboardButtonPollType object
2020-05-18 11:48:54 +05:00
783fe56566 Merge pull request #848 from Badiboy/master
Correct processing of bool parameters. Some timeouts added.
2020-05-16 17:45:30 +03:00
2368421332 Correct processing of bool parameters. Some timeouts added. 2020-05-16 17:34:56 +03:00
046276b491 Merge pull request #841 from drforse/master
fix test 1
2020-05-12 21:02:01 +03:00
3de8140c0b fix test 1 2020-05-12 18:29:36 +01:00
e5ad9ab383 Merge pull request #840 from drforse/master
fix test
2020-05-12 20:21:40 +03:00
d04e708438 fix test 2020-05-12 18:09:04 +01:00
200c6ccd07 Merge pull request #839 from drforse/master
add PollAnswer, poll_answer_handler
2020-05-12 19:56:22 +03:00
75a018e18b add PollAnswer, poll_answer_handler; make User Serializable and Dictionaryble; some pep fixes 2020-05-12 01:09:34 +01:00
aacc494a55 Merge pull request #834 from tohabyuraev/master
Bot API 4.5 partial support (in regards to chat).
2020-05-11 23:11:11 +03:00
ee00d0458d Fix some bugs 2020-05-11 22:26:03 +03:00
a60253bf60 UPG: Add ChatPermissions, set_chat_permissions 2020-05-11 16:38:09 +03:00
a80927baf9 UPG: add setChatAdministratorCustomTitle 2020-05-09 23:23:08 +03:00
8be9bcc8ed UPG: Add custom_title, slow_mode_delay 2020-05-09 20:28:29 +03:00
1824637617 UPG: Refactoring InlineKeyboardMarkup 2020-05-09 20:06:33 +03:00
df640966c2 Merge pull request #831 from Badiboy/master
Fix to_dic->to_dict refactoring
2020-05-09 00:54:22 +03:00
2849e67029 Fix to_dic->to_dict refactoring 2020-05-09 00:51:18 +03:00
d02de07142 Merge pull request #830 from tohabyuraev/newcon
Add BotCommand, setMyCommands
2020-05-08 22:06:24 +03:00
a56fb8cc54 UPG: Add BotCommand, setMyCommands 2020-05-08 21:06:39 +03:00
c5e5af96d1 Merge pull request #827 from CSRedRat/patch-1
Add handler decorator example
2020-05-07 18:01:39 +03:00
5d388f7ec4 Add handler decorator example 2020-05-07 19:56:17 +05:00
6c45511605 Update version 3.7.1 2020-05-02 19:41:46 +08:00
d8a08638a7 Merge pull request #821 from Badiboy/master
send_poll revised to standart signature
2020-05-02 13:35:34 +03:00
e2d70da694 Fix poll options serialization 2020-05-02 13:27:39 +03:00
6e1cf24946 send_poll revised to standart signature 2020-05-02 13:09:52 +03:00
be0fe94ee8 Merge pull request #819 from Badiboy/master
Fix Deprecation warning due to invalid escape sequences
2020-05-01 11:51:45 +03:00
ef81868ebc Fix Deprecation warning due to invalid escape sequences 2020-05-01 11:25:51 +03:00
57fb8d2fad Bump version. 3.7.0 2020-04-28 19:18:44 +08:00
c2590ab5ed Merge pull request #815 from bedilbek/remove-type-hinting
Remove type hinting for python 3.5 compatibility
2020-04-27 22:48:04 +03:00
24deb8a51d Change class from new-style class to object class 2020-04-28 00:34:52 +05:00
d7ebaa5bb3 Fix importing dependencies 2020-04-28 00:24:47 +05:00
601b570b85 Fix python2.7 compatibility for class inheritance 2020-04-28 00:22:05 +05:00
bdaabc4752 Merge pull request #814 from Badiboy/master
Travis update: remove Python 2
2020-04-27 22:01:37 +03:00
72d088940c Readme content fix 2020-04-27 22:00:20 +03:00
f1a960c56b Travis update: remove Python 2 2020-04-27 21:56:37 +03:00
bcc3a1afb4 Remove Type Hinting 2020-04-27 23:43:39 +05:00
d0edf44774 Merge pull request #813 from drforse/patch-1
Fix Dice test
2020-04-27 18:36:17 +03:00
9c87ed3679 fix test 2020-04-27 16:20:30 +01:00
67cfa04737 Merge pull request #812 from Badiboy/master
Disable REDIS tests to save Travis
2020-04-27 17:47:30 +03:00
be5d7bb73d Disable REDIS tests to save Travis
To enable REDIS set
test_handler_backeds.REDIS_TEST = True
before running tests.
2020-04-27 17:46:19 +03:00
f3a65ef9b3 Merge pull request #811 from drforse/master
update dice as the api has updated
2020-04-27 17:14:39 +03:00
99c63e9eba add emoji field for dice 2020-04-27 06:30:05 +01:00
e89a552e06 Merge pull request #810 from Badiboy/master
Polls are updated to the latest API state
2020-04-26 23:23:15 +03:00
bb4f6a7190 Polls are updated to the latest API state.
Polls are updated to the latest API state.

Minor code refactoring.
2020-04-25 22:22:08 +03:00
197dd2a582 add requests session for use torpy 2020-04-24 23:30:10 +05:00
dc3df70f9f Merge pull request #807 from Badiboy/master
Minor code refactoring (naming)
2020-04-24 18:21:54 +03:00
aac9ce45a3 Merge remote-tracking branch 'upstream/master' 2020-04-24 18:19:55 +03:00
24e984adf8 Minor code refactoring (naming) 2020-04-24 18:19:30 +03:00
1ed3bc2a53 Merge pull request #803 from noideaw/patch-2
added can_invite_users parameter to restrict_chat_member function param description
2020-04-24 18:16:25 +03:00
ce11b6f523 Merge pull request #806 from noideaw/patch-1
added can_invite_users parameter to restrict_chat_member function
2020-04-24 18:15:05 +03:00
8c7c7b31b2 Update __init__.py
added can_invite_users parameter to restrict_chat_member function
2020-04-24 19:38:23 +04:30
39e3be6673 Merge pull request #804 from noideaw/patch-3
Add can_invite_users to restrict_chat_member #1
2020-04-24 01:34:58 +03:00
b1b2726ef6 Update apihelper.py
added can_invite_users parameter to restrict_chat_member function
2020-04-24 00:21:05 +04:30
da924dbaeb Update __init__.py
added can_invite_users parameter to restrict_chat_member function
2020-04-23 23:59:04 +04:30
7966def331 Merge pull request #801 from bedilbek/fix-middleware-invocations
Fix not needed invocations on typed middleware handlers
2020-04-20 11:10:04 +03:00
aab560b4ee Fix all the time invocations on typed_middleware handlers even if update did not have that update_type message 2020-04-20 11:30:03 +05:00
646bbb8330 Merge pull request #794 from drforse/master
Add Dice and send_dice
2020-04-16 15:56:46 +03:00
339a5c01c1 Merge pull request #789 from bedilbek/step-handler-backend
HandlerBackend Mechanism Implementation
Codebase Refactoring
2020-04-16 15:53:11 +03:00
615402e4f8 return a line as it was 2020-04-15 06:16:07 +01:00
51b1fb7695 added Dice and send_dice 2020-04-15 06:10:05 +01:00
0881e34381 Refactor tests 2020-04-15 01:11:43 +05:00
3aec66bc0d Remove class static variable 2020-04-15 01:11:43 +05:00
e7e7c58133 Add Memory, File, Redis Backend tests 2020-04-15 01:11:43 +05:00
003c5db37f Add filename checking 2020-04-15 01:11:43 +05:00
286188f380 Add Step/Reply Handler Backend Mechanism
Implement Memory, File, Redis Backends
2020-04-15 01:11:43 +05:00
dd726b0759 Merge pull request #792 from Badiboy/master
Refactoring and API conformance
2020-04-14 22:22:48 +03:00
1bd9f5187c Merge pull request #787 from bedilbek/middleware-handler-readme
Middleware Handler README Update
2020-04-12 02:20:05 +03:00
68330c9a07 Update contents with middleware handler 2020-04-12 01:44:15 +05:00
b912e4dbaf Update with middleware handler 2020-04-12 01:41:34 +05:00
dab80d421b Refactoring update 2 2020-04-11 17:38:47 +03:00
247fe6e947 Refactoring bugfix 2020-04-11 17:06:14 +03:00
995814d846 Refactoring and API conformance
Refactoring.

new_chat_member is out of support.

Bugfix in html_text.

Started Bot API conformance checking.
2020-04-11 16:54:25 +03:00
36a228da92 Merge pull request #786 from Badiboy/master
Possibility to use alternative serializer
2020-04-11 16:52:53 +03:00
ec86182f62 Possibility to use alternative serializer
With apihelper.CUSTOM_SERIALIZER you can replace pickle with other "dumper" like dill.
2020-04-11 13:42:34 +03:00
2c385bf077 Merge pull request #785 from bedilbek/middleware-support
Add Middleware Handler
2020-04-11 11:20:58 +03:00
56cbc2ff93 Add examples to better understand middleware handler 2020-04-11 13:03:52 +05:00
932ac9477b Add ENABLE_MIDDLEWARE=False in apihelpers to keep backward compatibility 2020-04-11 13:02:50 +05:00
1e242f2263 Add Middleware support 2020-04-08 23:13:19 +05:00
862f17c716 Merge pull request #776 from irevenko/master
Add new bot in README
2020-03-28 01:15:50 +08:00
ed7cf30034 Add new bot in README 2020-03-27 16:38:22 +02:00
100f6d77f6 Merge pull request #767 from Tkachov/master
Add @bot.poll_handler to be notified of new poll states
2020-03-09 13:58:23 +03:00
d2f9c51a5a Handle Poll update 2020-03-09 17:25:54 +07:00
12547efa08 Fix order for consistency in process_new_updates 2020-03-09 17:25:37 +07:00
9410a3d310 Merge pull request #762 from Lin-Buo-Ren/patch-4
Use proper language for * query mentions in README
2020-03-01 21:14:32 +03:00
a4e5a09ab2 Use proper language for * query mentions in README
Signed-off-by: 林博仁(Buo-ren, Lin) <Buo.Ren.Lin@gmail.com>
2020-02-27 16:49:28 +08:00
ebfba49a8f Merge pull request #761 from Lin-Buo-Ren/patch-3
Fix missing padding space in code sample comments in README
2020-02-27 11:45:59 +03:00
6e6420a331 Merge pull request #760 from HolidayMan/patch-1
Some clarification of custom listeners working
2020-02-27 11:45:04 +03:00
7ca629dc10 Fix missing padding space in code sample comments in README
Signed-off-by: 林博仁(Buo-ren, Lin) <Buo.Ren.Lin@gmail.com>
2020-02-27 16:41:13 +08:00
3ecb7cef3b Some clarification of custom listeners working 2020-02-27 00:59:21 +02:00
e789407774 Merge pull request #743 from Quantum-0/master
Add is_anonymous flag to Poll type
2020-02-14 16:49:54 +03:00
8f32dec5dd Merge pull request #744 from FaeeLoL/master
Add missed colon in readme
2020-02-14 16:48:44 +03:00
c57cfa3949 Add missed colon 2020-02-08 17:44:28 +03:00
dfac26706e Add is_anonymous flag to Poll type 2020-02-07 12:53:31 +03:00
385fa98bc6 Merge pull request #738 from andrey18106/patch-1
Added missed bracket
2020-01-30 01:10:51 +03:00
d68e89fc9a Added missed bracket 2020-01-28 20:56:03 +02:00
6023bae728 Merge pull request #735 from Lin-Buo-Ren/patch-2
Fix typo in README
2020-01-24 23:01:07 +03:00
b323a868f0 Fix typo in README
Signed-off-by: 林博仁(Buo-ren, Lin) <Buo.Ren.Lin@gmail.com>
2020-01-17 17:21:30 +08:00
583021d114 Update version to 3.6.7, 2020-01-14 16:33:05 +08:00
b1e5d00821 Merge pull request #728 from Badiboy/master
Design updates from #711
2020-01-08 20:29:12 +03:00
aa02ddb573 TAB fix
TAB fix
2020-01-08 20:17:25 +03:00
760ea5a2f0 Design updates from #711
Significant design updated from
https://github.com/eternnoir/pyTelegramBotAPI/pull/711
2020-01-08 20:06:40 +03:00
9b279dc562 Merge pull request #726 from Badiboy/master
Update test_types.py
2020-01-03 19:31:39 +03:00
5cd97ebc96 Update detailed_example.py
Vulgarity replaced.
2020-01-03 19:24:10 +03:00
b5ba2445d3 Update test_types.py
Updated test vectors for stickers.
2020-01-03 19:18:18 +03:00
7adec8bd90 Merge pull request #673 from TahaPY/master
Added Animation and is_animated for stickers
2020-01-03 17:51:53 +03:00
0603a0df4c Update types.py
Animation is moved before document to save backward compatibility. content_type = 'document' should override content_type = 'animation' to save previous behaviour.
2020-01-03 17:51:05 +03:00
59810b5e2a Merge pull request #620 from nev3rfail/send_animation
Added reduced version of sendAnimation (no width/height/thumb).
2020-01-03 17:12:29 +03:00
b999fea2ac Merge pull request #703 from voskresla/patch-1
Using Azure Functions for serverless bots.
2020-01-03 16:59:09 +03:00
a41dabf73c Merge pull request #725 from cclauss/patch-1
Travis CI: Drop EOL Py34 and add current Py38
2020-01-03 16:53:18 +03:00
5407801f62 Merge pull request #708 from xxsokolov/patch-1
Remove unused base_url from _make_request. Fixed misc error.
2020-01-03 16:52:47 +03:00
2efb33fc29 Merge branch 'master' into patch-1 2020-01-03 16:45:43 +03:00
620ea5dee0 Travis CI: Drop EOL Py34 and add current Py38 2020-01-03 14:36:08 +01:00
eaf44f1a6b Merge pull request #724 from Badiboy/master
Update version list in travis.yml
2020-01-03 02:08:00 +03:00
8c62b99057 Update .travis.yml
Travis: removed 2.6 and 3.3 (not supported). Added 3.7. Also added 3.8 (for experiment)
2020-01-03 02:05:32 +03:00
e3b126807e Merge pull request #713 from dtalkachou/patch-1
Correct work with empty base_url in make_request
2020-01-03 01:33:27 +03:00
769ff8008e Merge pull request #599 from KanerL/KanerL-patch-shipping-option
ShippingOption.add_price returns "self" (for chaining etc.).
2020-01-03 01:28:37 +03:00
0e0e2d97c0 Merge pull request #715 from Pablohn26/patch-1
Change chatid to chat_id to be the same as other examples
2020-01-03 01:19:47 +03:00
bb199024fd Merge pull request #593 from neoranger/patch-2
Update README.md
2020-01-03 01:02:35 +03:00
86644c05f7 Merge pull request #539 from Badiboy/master
"timeout" parameter for send_message
Fix kick_chat_member return type
HTML symbols not replaced
2020-01-03 00:50:24 +03:00
3a3bab5b92 Merge pull request #480 from SkymanOne/patch-1
create field forward_from_message_id in Message
2020-01-03 00:46:27 +03:00
bf844ed202 HTML symbols not replaced
HTML symbols not replaced because return is before replace.
2020-01-01 13:46:18 +03:00
fefb9d4555 Merge pull request #723 from LeoSvalov/master
Update README
2019-12-28 12:34:14 +08:00
a413a51221 Update README
Adding another bot that user pyTelegramBotAPI.
2019-12-24 16:25:58 +05:00
a71030dcdd Change chatid to chat_id to be the same as other examples
Change in README.md chatid to chat_id to be the same as other examples
2019-11-30 05:51:56 +01:00
68db599790 Delete duplicate string 2019-11-23 21:25:29 +03:00
a749acde15 Update apihelper.py #2
Merge Fixes # 684
2019-11-05 17:37:53 +03:00
5935a378ca Merge pull request #685 from cclauss/patch-1
Use ==/!= to compare str, bytes, and int literals
2019-10-30 21:26:00 +08:00
1dd94d6e6d Merge pull request #667 from desexcile/patch-2
Update Readme
2019-10-30 21:25:11 +08:00
2fb0f3fb4b Merge pull request #684 from xxsokolov/patch-1
Update apihelper.py
2019-10-30 21:24:51 +08:00
575fb9da7f Merge branch 'master' into patch-1 2019-10-30 21:24:43 +08:00
c6358f35d2 Merge pull request #688 from vryazanov/master
New content type related to Telegram Passport
2019-10-30 21:22:36 +08:00
20b87f2242 Merge pull request #701 from eternnoir/dependabot/pip/requests-2.20.0
Bump requests from 2.7.0 to 2.20.0
2019-10-30 21:22:16 +08:00
f4c215b0b8 Merge pull request #705 from keshamin/fix-578
Fixed #578
2019-10-30 21:21:49 +08:00
1a30a9a249 Fixed #578 2019-10-30 14:02:00 +03:00
e644ed910a Using Azure Functions for serverless bots.
Simple echo bot using Azure Functions as webhook.
2019-10-13 23:49:43 +03:00
8cb2da3775 Bump requests from 2.7.0 to 2.20.0
Bumps [requests](https://github.com/requests/requests) from 2.7.0 to 2.20.0.
- [Release notes](https://github.com/requests/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/master/HISTORY.md)
- [Commits](https://github.com/requests/requests/compare/v2.7.0...v2.20.0)

Signed-off-by: dependabot[bot] <support@github.com>
2019-10-05 11:55:18 +00:00
f8e7c0f819 Merge branch 'master' into patch-2 2019-09-23 10:25:18 -03:00
f241ef1eac passport_data content type added 2019-08-27 11:55:14 +03:00
8f8276314e Merge pull request #1 from cmd410/master
Support for animated stickers
2019-08-16 20:42:08 +00:00
9e30cfbda6 Use ==/!= to compare str, bytes, and int literals
Identity is not the same thing as equality in Python.
2019-08-12 22:47:59 +02:00
6fb9e18385 Update apihelper.py
Hi, to indicate a third-party api-url (reverse proxy) added conditions.
Perhaps not the most elegant solution, but this functionality is very lacking.


apihelper.API_URL = "http://reverseproxy.example.com/bot{0}/{1}"
2019-08-12 17:09:52 +03:00
f0835a1a14 Support for animated stickers 2019-07-30 12:46:39 +03:00
be3b6f88e8 Added Animation 2019-07-14 18:53:59 +04:30
87e811ce3e Update Readme
Fixed source link
2019-06-29 09:39:14 +03:00
151880f391 Merge pull request #659 from OslikAi/master
Add Poll
2019-06-28 21:02:23 +08:00
bf91829088 Merge pull request #664 from vovawed/master
Added LoginUrl to types
2019-06-28 21:02:04 +08:00
56f0b0a0d4 Merge pull request #603 from nailerNAS/master
infinity_polling fix
2019-06-28 20:57:28 +08:00
2b8e77f749 Merge pull request #616 from painca/patch-1
edit message_handler doc
2019-06-28 20:56:47 +08:00
fba425265e Merge pull request #645 from setazer/patch-1
remove unnecessary f-strings
2019-06-28 20:56:29 +08:00
23069ac729 Merge pull request #644 from David-Lor/master
update bot list
2019-06-28 20:56:15 +08:00
7ab93f55a6 Merge pull request #666 from desexcile/patch-1
Update Readme
2019-06-28 20:55:46 +08:00
ba2705dc82 Merge remote-tracking branch 'origin/master' 2019-06-27 15:07:54 +03:00
3a1bdc2899 add Poll, sendPoll, stopPoll 2019-06-27 15:07:41 +03:00
4e57adbcb6 Update Readme
added @asadov_bot to Bot list using this Api
2019-06-26 10:54:59 +03:00
600002e158 Fixed bug with LoginUrl 2019-06-15 23:09:59 +03:00
3c62e9d391 Added LoginUrl to types 2019-06-15 22:59:41 +03:00
63df69aeb8 Delete my_tests.py 2019-06-06 22:23:11 +03:00
a8cf9f4ae5 Update README.md 2019-06-06 21:54:06 +03:00
b10e45f714 add Poll, sendPoll, stopPoll 2019-06-06 21:49:06 +03:00
9624b45314 add Poll, sendPoll, stopPoll 2019-06-06 21:47:08 +03:00
e26ad07965 Merge pull request #658 from FacuM/add_bot_patch
Update README.md
2019-05-31 11:24:14 +08:00
55c7b6373c Update README.md 2019-05-30 00:35:57 -03:00
ceceeb7d8c Update README.md 2019-05-24 15:05:20 +08:00
b76a69e036 Merge pull request #624 from kor0p/editMessageText
Add 'method' parameter to methods that edit message
2019-05-18 07:58:56 +08:00
e5700380bd Merge branch 'master' into master 2019-05-18 07:56:53 +08:00
47b53b8812 Merge pull request #649 from karipov/master
added creationdatebot to bots api list
2019-04-24 17:41:43 +08:00
2d0ebde481 added creationdatebot to bots api list 2019-04-24 11:29:52 +02:00
271b7e0642 Merge pull request #646 from airatk/master
Update README.md
2019-04-23 10:15:02 +08:00
f516438360 Update README.md 2019-04-21 18:34:10 +03:00
7dc9abffc6 remove unnecessary f-strings 2019-04-16 07:38:50 +07:00
2285d0466e update bot list
Remove areajugonesbot; add vigobustelegrambot
2019-04-09 11:32:15 +02:00
31dbe30489 Merge pull request #629 from iv8/patch-1
fix errors
2019-04-07 21:43:41 +08:00
iv8
c77307881d fix errors 2019-03-04 15:24:55 +08:00
1a58731fb7 Add 'method' parameter to methods that edit message 2019-02-23 16:15:20 +02:00
99df992a66 Added the method sendAnimation, which can be used instead of sendDocument to send animations, specifying their duration. 2019-02-15 18:46:18 +00:00
79e6a3166d edit message_handler doc 2019-01-20 23:04:11 +05:00
8005ca2f6c Update example for api server check webhook alive. 2018-12-29 23:49:10 +08:00
b82ed70ec9 fix syntax errors 2018-11-17 13:19:09 +02:00
18e37f3d20 sleep time timeout time instead of 5 seconds always 2018-11-17 12:58:56 +02:00
ceea457cf1 Update shipping option
Setting list of ShippingOptions like in payments_example.py
shipping_options = [
    ShippingOption(id='instant', title='WorldWide Teleporter').add_price(LabeledPrice('Teleporter', 1000)),
    ShippingOption(id='pickup', title='Local pickup').add_price(LabeledPrice('Pickup', 300))]
gives us [None,None],so It's better add_price to return self
2018-11-12 01:43:00 +02:00
4131b05733 Update README.md
Adding another bot that user pyTelegramBotAPI.
2018-11-05 15:11:31 -03:00
ad4be5c0ae Merge branch 'master' of https://github.com/eternnoir/pyTelegramBotAPI 2018-10-19 13:40:14 +03:00
a946b79839 Merge pull request #586 from khode-mohsen/patch-2
Update deep_linking.py
2018-10-19 10:08:05 +08:00
4eeca78f2f Merge pull request #585 from khode-mohsen/patch-1
Update echo_bot.py
2018-10-19 10:07:55 +08:00
2d6c2a345f Merge pull request #577 from rmed/master
Add check for parse_mode in BaseInlineQueryResultCached
2018-10-19 10:07:40 +08:00
e62eeb7ff2 Merge pull request #565 from uburuntu/analyzer-fixes
Some analyzer fixes
2018-10-19 10:06:37 +08:00
76fc8fbe5e Update deep_linking.py
add '#!/usr/bin/python' for direct execute
2018-10-19 03:47:19 +03:30
584955962e Update echo_bot.py
add '#!/usr/bin/env' for direct execute
2018-10-19 03:38:03 +03:30
b8f442d06b Update Bots using this API 2018-10-09 17:32:27 +08:00
891988be93 Added check for parse_mode in BaseInlineQueryResultCached. Should fix #571 2018-09-15 20:25:06 +02:00
8636b282d7 Merge branch 'master' into analyzer-fixes 2018-09-07 18:07:37 +03:00
2c57c5c01c Update version. 2018-09-07 16:02:03 +08:00
07b82dc9b0 Merge pull request #575 from uburuntu/reset_session
Reset requests.Session feature
2018-09-07 15:56:59 +08:00
a850a0d94f Merge pull request #554 from uburuntu/patch-1
Pretty formatted docs for PyPI
2018-09-07 15:55:23 +08:00
d4f1444503 Merge pull request #574 from setazer/master
fix typo + add inline keyboard example
2018-09-07 15:54:11 +08:00
bab9f7bbb9 enh: reset requests.Session feature
Need for proxy changing and other reconnection stuff
2018-09-06 12:48:08 +03:00
d9ace2adc8 fix typo + add inline keyboard example 2018-09-05 12:34:19 +07:00
36621bb22a fix: some intendation 2018-08-17 13:01:03 +03:00
99466017c5 enh: optimize imports 2018-08-17 12:54:26 +03:00
feec1dde56 fix: little style fixes 2018-08-17 12:49:37 +03:00
54eba946be fix: wrong arguments usage (fix fa038c2) 2018-08-17 12:48:59 +03:00
65a272b901 fix: python 2/3 compatibility in examples 2018-08-17 12:47:44 +03:00
6a4c7e731b fix: delete doubled Sticker class (left a new one) 2018-08-17 12:46:40 +03:00
2b3c86b647 Merge pull request #562 from uburuntu/InputMedia
fix: python2 positional argument specifiers
2018-08-14 22:37:39 +08:00
e419214b49 fix: python2 positional argument specifiers 2018-08-14 17:29:35 +03:00
fe6959c38e Merge pull request #561 from uburuntu/InputMedia
fix: support python2 super()
2018-08-14 21:58:48 +08:00
7dd53b1396 fix: support python2 super() 2018-08-14 12:23:15 +03:00
421118d9d8 Merge pull request #558 from uburuntu/InputMedia
v.4.0: InputMediaAnimation, InputMediaAudio, InputMediaDocument, editMessageMedia
2018-08-13 23:47:03 +08:00
cf69a06ab8 enh: make code better and enhance test case 2018-08-10 16:48:09 +03:00
8ac6e664c5 new: InputMediaAnimation, InputMediaAudio, InputMediaDocument, editMessageMedia
Added support for editing the media content of messages: added the method editMessageMedia and new types InputMediaAnimation, InputMediaAudio, and InputMediaDocument.
2018-08-09 19:16:38 +03:00
12dbcb56d3 Update README.md 2018-08-09 08:45:07 +08:00
a46975d038 Merge pull request #556 from Andru1999/patch-2
Fix issue When you use threading mode
2018-08-08 10:06:49 +08:00
494b535a91 Fix issue When you use threading mode 2018-08-08 10:46:23 +10:00
74f75884f3 Delete now unused deprecated README.rst 2018-08-06 13:56:38 +03:00
4eae469528 Use last version of README.md for PyPI docs with pretty formatting
https://packaging.python.org/specifications/core-metadata/#description-content-type
https://pypi.org/project/pyTelegramBotAPI/
2018-08-06 13:54:46 +03:00
41f7c07959 Update version. 2018-08-03 08:35:04 +08:00
35ea2a2b7e Fix #548 2018-08-03 08:34:48 +08:00
522b2b487b Merge pull request #551 from heyyyoyy/origin/Bot_Api_3.6
Added parse mode for objects in Inline mode
2018-08-03 08:30:41 +08:00
5035e0ce80 Added parse mode for objects in Inline mode 2018-08-02 21:15:33 +03:00
7061091c1c Update version.
* Fix python 3.7 async
2018-07-31 08:58:04 +08:00
5c199bd246 Update README.md 2018-07-26 22:17:55 +08:00
44dd89881d Update README.md 2018-07-26 21:41:08 +08:00
8634e65249 Fix kick_chat_member decription
Fix kick_chat_member return value type description (should be boolean according to API and is boolean by fact).
2018-07-25 12:44:18 +03:00
76dbb05259 Merge pull request #537 from Andru1999/patch-1
Update __init__.py
2018-07-24 13:05:02 +08:00
578a9383b2 Merge branch 'master' into patch-1 2018-07-24 10:42:04 +08:00
85093bded5 Merge pull request #515 from WaffleWafflerov/master
Saving next step and reply handlers
2018-07-24 10:39:35 +08:00
27d442fabf timeout for send_message
Add optional "timeout" parameter to send_message (the same as exists in all other send_*).

Equal rights for all send functions! :)
2018-07-24 00:33:13 +03:00
f251def304 Merge branch 'master' into master 2018-07-22 04:43:53 +03:00
2b822f782d Update __init__.py
I find bug when I use your library without threading. If call bot.register_next_step_handler in function that register next_handler in next_step_handlers but in function _notify_next_handlers this delete and bot don`t have handler, but in threading mode function self.next_step_handlers.pop(chat_id, None) has time to eval self.next_step_handlers.pop(chat_id, None) and bug disappear. Sorry for my English
2018-07-22 00:31:02 +10:00
8bc5b74495 Remove 3.7 stable. Travis ci not support now. 2018-07-03 22:34:28 +08:00
70426ac274 Merge pull request #526 from skar404/master
rename async -> async_dec
2018-07-03 11:19:29 +08:00
a3a2bd5793 Add python 3.7 in travis ci.
#527
2018-07-03 11:17:44 +08:00
c3b6ee9dc0 bug in travis-ci 2018-07-02 23:41:37 +03:00
4079772fd3 Update .travis.yml 2018-07-02 23:29:07 +03:00
9547a8d7b1 test python 3.7 2018-07-02 23:23:48 +03:00
c8b2b14157 rename async -> async_dec 2018-07-02 18:13:11 +03:00
3d5ef5b1d8 Merge pull request #516 from Badiboy/master
_notify_next_handlers drops messages if empty handler list
2018-05-31 14:04:45 +08:00
776a699a8d _notify_next_handlers skips sequential messages
Is there are several sequential messages and next_step_handlers are set, the _notify_next_handlers will process only every even message dew to execute both .pop(i) and i+=1
2018-05-29 18:55:41 +03:00
78afd045d8 _notify_next_handlers drops messages if empty handler list
After calling
clear_step_handler(...)
code:
self.next_step_handlers[chat_id] = []
left the key in next_step_handlers.
When a next message arrives, the old handler executes nothing (no handlers), but still remove message from message queue:
new_messages.pop(i).

Updated to pop message only when there are real handlers in the list.
2018-05-27 23:24:37 +03:00
06faed887c Merge pull request #509 from Badiboy/master
html_text fix and html_caption
2018-05-27 23:14:37 +08:00
bc855f7610 Fix register_for_reply_by_message_id and register_for_reply doc strings. 2018-05-27 17:05:01 +03:00
893d5386c5 Fix register_for_reply_by_message_id doc strings. 2018-05-27 17:02:04 +03:00
909d570dca Add warning about lambda functions in callbacks 2018-05-27 17:01:07 +03:00
424c77fd2c Remove type hint for 2.x and PyPy python compatibility 2018-05-27 16:54:56 +03:00
333949683f Add doc strings to new TeleBot methods
Update telebot/__init__.py
2018-05-27 01:37:06 +03:00
fa038c2e42 Move del_file_after_loading param to right methods :face_palm:
Update: telebot/__init__.py
2018-05-27 01:30:14 +03:00
d61de35a32 Remove rudiment json things, again!
Update: telebot/__init__.py
2018-05-27 01:23:20 +03:00
13df7b5908 Add enable_save_next_step_handlers and load_next_step_handlers methods to step_example/
Update: examples/step_example.py
2018-05-26 17:21:39 +03:00
1de356dcc3 Change default save directory to "./.handler-saves/".
Add del_file_after_loading param to load methods.

Update: telebot/__init__.py
2018-05-26 17:10:00 +03:00
47e6dfd6bc Remove rudiment json things
Update: telebot/__init__.py
2018-05-26 16:52:30 +03:00
3c890a7846 Remove 2 spaces up to TeleBot class.
Update: telebot/__init__.py
2018-05-26 16:37:25 +03:00
17971ff48b Move from json to pickle.
Update: relebot/__init__.py
2018-05-26 12:19:01 +03:00
b989b7601b Add new class: Handler
Change type of (next step|reply) handlers from dict to Handler [WIP]

update: telebot/__init__.py
2018-05-25 20:57:22 +03:00
8c574a786a Merge branch 'master' of https://github.com/WaffleWafflerov/pyTelegramBotAPI-1 2018-05-25 20:37:36 +03:00
7e5f51e4ab Remove old thing.
Update telebot/__init__.py
2018-05-25 09:44:43 +03:00
018e4597a2 Add del_file_after_loading param to Saver.return_load_handlers and Saver.load_handlers methods.
Update telebot/__init__.py
2018-05-25 09:40:29 +03:00
7df6b3d4c9 Fix situation where delay <= 0.
Update telebot/__init__.py
2018-05-25 09:35:39 +03:00
4facc5f7d7 fix unenabled saving handlers.
Updated telebot/__init__.py
2018-05-25 09:30:10 +03:00
4bcfc34a50 Update _notify_next_handlers and _notify_reply_handlers methods:
Now if there wasn't any handler updates, timer willn't start.
2018-05-25 09:07:59 +03:00
b1d5cb2129 Rewrite.
Add class 'Saver' that provides methods for saving (next step|reply) handlers.
Add methods
enable_save_next_step_handlers,
enable_save_reply_handlers,
disable_save_next_step_handlers,
disable_save_reply_handlers,
load_next_step_handlers,
load_reply_handlers
to Telebot and AsyncTelebot.

update telebot/__init__.py
2018-05-25 08:57:48 +03:00
00c8dcc19b Add async methods 2018-05-25 03:10:40 +03:00
ed7e33b4c6 Fix loadings funcs 2018-05-25 02:48:46 +03:00
74a952846c Merge branch 'master' of https://github.com/CoconutWaffle/pyTelegramBotAPI-1 2018-05-24 18:32:25 +03:00
e99fb8f84f Add methods to save (reply|next step) handlers [WIP] 2018-05-20 23:40:25 +03:00
49aee14fca Make _test_filter method static and a bit clear doc strings 2018-05-19 00:42:06 +03:00
9267da205d Merge pull request #1 from eternnoir/master
Updating fork
2018-05-19 00:35:58 +03:00
9c79ba2f87 html_text fix and html_caption
html_text now works with text_link
html_caption now works for caption/caption_entities
2018-05-14 13:29:34 +03:00
3be21ae361 Update version. 2018-05-14 10:15:05 +08:00
42343c3a7f Merge pull request #490 from CoconutWaffle/master
Fixing and upgrading next step and reply handlers. + minor fixes
2018-05-04 07:20:18 +08:00
5a102ed8fa Merge pull request #492 from sviat9440/master
Bugfixes (message.html_text offset)
2018-05-04 07:19:28 +08:00
e1e109bef1 Merge pull request #502 from fojetin/patch-1
Fix #253 #231 #485
2018-05-04 07:18:57 +08:00
b5a217013a Fix #253 #231 #485 2018-04-30 15:41:12 +03:00
3ba9799b98 Renaming back pytelegrambotapi module to telebot 2018-04-28 13:50:59 +03:00
91f213ff34 Fix #501 2018-04-27 15:47:03 +08:00
8f55460924 Fix cache time is zero. 2018-04-26 09:53:55 +08:00
f6b999053d Merge pull request #497 from khabibr/master
Update apihelper.py
2018-04-24 23:52:45 +08:00
99ff104a3f Update apihelper.py
Correct files downloading when proxy used.
2018-04-24 16:48:39 +06:00
662c2c8797 Merge pull request #495 from BennyThink/master
fix issue #403: UnicodeEncodeError when sending a non-ASCII file in Python 2
2018-04-18 20:05:19 +09:00
72a0199a2f Merge pull request #496 from Jay-T/master
Update README.md
2018-04-18 20:04:27 +09:00
989cae597b Update README.md 2018-04-18 13:10:22 +05:00
5dd88f8223 fix issue #403: UnicodeEncodeError when sending a non-ASCII file in Python 2.7 2018-04-18 15:00:05 +08:00
28111bdf4e Merge pull request #494 from LeoNeeDpk1/patch-1
Update README.md SOCKS5 proxy info
2018-04-18 11:51:44 +09:00
10ec897fb5 Update README.md
Updated and 100% working info in SOCKS5 proxy block.
2018-04-18 10:05:26 +12:00
ffe3a0c3d7 Update types.py
-- Fix encoding bug (emoji shifted offset)
2018-04-15 19:19:29 +03:00
f5f48db6ba Merge pull request #1 from eternnoir/master
Update
2018-04-15 19:17:46 +03:00
183230e927 Update setup.py 2018-04-12 17:24:04 +03:00
7957bc45a8 Fixing and upgrading next step and reply handlers. + minor fixes
Rename telebot package to pytelegrambotapi becouse lib named telebot exists and it raising many errors

Add methods:
|     register_for_reply_by_message_id,
|     register_next_step_handler_by_chat_id,
|     clear_reply_handlers,
|     clear_reply_handlers_by_message_id
2018-04-12 13:45:32 +03:00
373d4d37ff Fix test case. 2018-04-10 14:48:39 +08:00
0d0e37dae5 Merge pull request #487 from sviat9440/master
Bugfixes and minor improvements
2018-04-10 15:25:36 +09:00
36d088dfbf Bugfixes and minor improvements 2018-04-04 10:47:37 +03:00
9ae20b4815 Merge pull request #482 from sviat9440/master
Minor improvements
2018-03-25 21:39:27 +08:00
e761e1e1d9 Update apihelper.py 2018-03-25 14:54:28 +03:00
cb0256b37d Update __init__.py 2018-03-25 13:22:35 +03:00
ff3cbaf45b Update apihelper.py 2018-03-25 13:21:55 +03:00
d231b1fbaa Bump version. 2018-03-23 19:59:42 +08:00
7f47f11444 Fix #481 2018-03-23 19:58:43 +08:00
0422e62f65 Update types.py
Fix
2018-03-21 10:45:34 +03:00
82e252ec46 Update types.py
Fix
2018-03-21 10:44:37 +03:00
c11a9f810c Update types.py
Added 'json' property to class 'Message', to quickly save a message to the database
2018-03-21 07:35:42 +03:00
d17d28a144 create field forward_from_message_id in Message
https://core.telegram.org/bots/api#message
2018-03-20 23:36:29 +03:00
dadcd5a577 Update "Bots using this API" entry. 2018-03-19 15:13:48 +08:00
afc9abc269 Add ci test for python 3.6 2018-03-10 14:48:30 +08:00
e01f17e3a0 Bump version. 2018-03-10 14:46:47 +08:00
48e6757686 Fix import logger problem. 2018-03-10 14:41:34 +08:00
8495229ce1 Update version 3.6.0 2018-03-02 19:28:34 +08:00
3b60f7ca67 Merge pull request #462 from heyyyoyy/Bot_Api_3.6
Bot Api 3.6
2018-02-22 22:11:46 +08:00
a1930e05c2 Merge pull request #463 from dmytrostriletskyi/master
Make the Heroku example actual
2018-02-22 20:52:53 +08:00
bc067662dc Make the Heroku example actual 2018-02-16 17:52:37 +02:00
518c49f23a fixing formatting of caption in the method send_document 2018-02-16 18:29:29 +03:00
903b1dfd50 added parse_mode in edit_message_caption 2018-02-16 14:19:35 +00:00
2e199a5684 Bot Api 3.6 2018-02-14 20:27:55 +00:00
55302cb972 Merge pull request #445 from heyyyoyy/update_send_media_group
Added support for local files in the sendMediaGroup method
2018-02-01 19:24:50 +08:00
f47653d2e4 Update README.md 2018-01-24 19:13:29 +08:00
94b4a25980 Update version. 2018-01-24 19:11:03 +08:00
afac177d7d Fix missing media_group_id in message. 2018-01-24 19:05:38 +08:00
2637e29dbe Updated sendMediaGroup method 2018-01-15 16:08:50 +03:00
6d180e30f0 Merge pull request #443 from reacheight/master
fixed example of usage sendVideoNote method
2018-01-15 10:25:06 +08:00
e2ed4cf065 Merge pull request #387 from fumycat/patch-1
Fix optional parameter
2018-01-15 10:23:26 +08:00
8b2dea1d56 fixed example of usage sendVideoNote method 2018-01-10 00:26:44 +03:00
41e31de034 Merge pull request #429 from JekaFST/master
Fix for SendLocation with live period
2017-12-06 15:50:49 +08:00
ae074fd5c9 Merge pull request #2 from JekaFST/JekaFST-live_location_fixes
Edit and stop live location fixes
2017-12-05 01:32:06 +03:00
60596a95b8 Edit and stop live location fixes
.token was missed in apihelper's methods calls
2017-12-05 01:31:47 +03:00
44531bcedf Merge pull request #1 from JekaFST/JekaFST-FixLiveLocation
Fix for SendLocation with live period
2017-12-05 00:23:32 +03:00
8aa8fa5986 Fix for SendLocation with live period
Fix for payload['live_perion'] typo -> payload['live_period']
2017-12-05 00:21:05 +03:00
f0e64b3653 Merge pull request #428 from 0xVK/patch-1
Added SmartySBot to README
2017-12-04 16:21:41 +08:00
8444ea588a Added SmartySBot to README
Added SmartySBot to README
2017-12-03 20:34:37 +02:00
b2f376a906 Remove debug message. Add content_type 2017-11-30 23:34:07 +08:00
d0b4bb7c69 Bump version. 2017-11-29 14:09:57 +08:00
c300195b49 Add provider_data . 2017-11-29 13:59:47 +08:00
2493b200a4 Add provider_data to sendInvoice. 2017-11-29 13:53:39 +08:00
8528ca9e4e Add some message content type. Fix #426 2017-11-29 13:48:34 +08:00
e1a3ccadb7 Add sendMediaGroup method. 2017-11-29 13:45:25 +08:00
a43f037bc9 Version update. 2017-11-15 00:42:50 +08:00
7ac246b801 Fix inline_query_handler not work. 2017-11-15 00:42:27 +08:00
47624a556e Update version. 2017-11-13 10:26:27 +08:00
8bdbc24014 Fix ShippingOption to_json. #414 2017-11-13 10:25:39 +08:00
e45ced958a Update version to support 3.4. 2017-11-13 10:19:13 +08:00
46c803bf55 Fix shipping_options bug. #414
Update version.
2017-11-13 10:14:10 +08:00
3986f33d3a Fix caption_entities without default value. 2017-11-06 08:42:57 +08:00
c327be5a03 Merge pull request #410 from 0xVK/fix-exec-handlers
#405 - Message has callback function but it exec command handlers too.
2017-11-04 21:28:21 +08:00
d8587419e1 Fixed bug when message has next step handler and exec command handlers. 2017-11-04 15:09:29 +02:00
35d7293ebd Merge pull request #402 from MasterGroosha/master
Bot API 3.4: new methods for live locations, new objects.
2017-10-31 09:51:23 +08:00
8e71a612a6 Added missing methods definitions to __init__.py and Async Telebot 2017-10-22 20:07:51 +03:00
5f8d99664e Bot API 3.4: new methods for live locations, new objects. 2017-10-22 19:50:51 +03:00
aaa968c27f Merge pull request #396 from MasterGroosha/patch-1
Added missing author_signature field to Message object
2017-09-25 16:42:38 +08:00
600c014515 Added missing author_signature field to Message object
`author_signature` field was checked, but never added to `Message` object.
2017-09-22 01:08:54 +03:00
0a80fafd76 Update README.md 2017-09-09 21:32:13 +08:00
4a11bb60b4 Update new_chat_member to new_chat_members 2017-09-08 15:47:16 +08:00
7d37374667 Fix test case. 2017-08-28 12:13:26 +08:00
6ad56eb30f Merge pull request #392 from MasterGroosha/master
Bot API 3.3
2017-08-28 11:50:25 +08:00
211f1c607d Bot API 3.3:
- Added the new field pinned_message to the Chat object.
- Added the new fields author_signature and forward_signature to the Message object.
- Added the new field is_bot to the User object.
2017-08-23 10:30:32 +03:00
be786021dc Merge pull request #389 from mostafaqanbaryan/patch-1
Update __init__.py
2017-08-22 04:06:08 +07:00
15d287919d Update __init__.py
Add clear_step_handler() for resetting bot
2017-08-21 14:40:47 +04:30
af991ea76e Fix optional parameter 2017-08-20 01:36:08 +07:00
064b84ad3d Merge pull request #377 from GabrielRF/master
Update README.md
2017-08-13 00:40:50 +08:00
39b4f0a068 Merge branch 'master' into master 2017-08-10 15:03:39 -03:00
246e7e31d7 Update README.md 2017-08-08 21:50:54 +08:00
48bfb7b84f Update version. 2017-08-06 15:47:59 +08:00
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
e92dc3717e Update README.md 2017-07-24 14:28:27 -03: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
73 changed files with 15930 additions and 1612 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?

35
.github/workflows/setup_python.yml vendored Normal file
View File

@ -0,0 +1,35 @@
# This is a basic workflow to help you get started with Actions
name: Setup
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [ master ]
pull_request:
branches: [ master ]
# Allows you to run this workflow manually from the Actions tab
#workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
all-setups:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ '3.6','3.7','3.8','3.9', 'pypy-3.6', 'pypy-3.7' ] #'pypy-3.8', 'pypy-3.9' NOT SUPPORTED NOW
name: ${{ matrix.python-version }} and tests
steps:
- uses: actions/checkout@v2
- name: Setup python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
architecture: x64
- run: |
pip3 install -r requirements.txt
python setup.py install
cd tests && py.test

7
.gitignore vendored
View File

@ -25,6 +25,7 @@ var/
.idea/
venv/
.venv/
# PyInstaller
# Usually these files are written by a python script from a template
@ -58,4 +59,8 @@ docs/_build/
# PyBuilder
target/
testMain.py
testMain.py
#VS Code
.vscode/
.DS_Store

View File

@ -1,10 +1,10 @@
language: python
python:
- "2.6"
- "2.7"
- "3.3"
- "3.4"
- "pypy"
- "3.6"
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "pypy3"
install: "pip install -r requirements.txt"
script:

566
README.md
View File

@ -1,12 +1,19 @@
[![PyPi Package Version](https://img.shields.io/pypi/v/pyTelegramBotAPI.svg)](https://pypi.python.org/pypi/pyTelegramBotAPI)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/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)
[![PyPi downloads](https://img.shields.io/pypi/dm/pyTelegramBotAPI.svg)](https://pypi.org/project/pyTelegramBotAPI/)
# <p align="center">pyTelegramBotAPI
<p align="center">A simple, but extensible Python implementation for the [Telegram Bot API](https://core.telegram.org/bots/api).
<p align="center">A simple, but extensible Python implementation for the <a href="https://core.telegram.org/bots/api">Telegram Bot API</a>.</p>
<p align="center">Supports both sync and async ways.</p>
[![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)
[![Download Month](https://img.shields.io/pypi/dm/pyTelegramBotAPI.svg)](https://pypi.python.org/pypi/pyTelegramBotAPI)
## <p align="center">Supporting Bot API version: <a href="https://core.telegram.org/bots/api#november-5-2021">5.4</a>!
* [Getting started.](#getting-started)
## Contents
* [Getting started](#getting-started)
* [Writing your first bot](#writing-your-first-bot)
* [Prerequisites](#prerequisites)
* [A simple echo bot](#a-simple-echo-bot)
@ -15,25 +22,48 @@
* [Methods](#methods)
* [General use of the API](#general-use-of-the-api)
* [Message handlers](#message-handlers)
* [Edited Message handler](#edited-message-handler)
* [Channel Post handler](#channel-post-handler)
* [Edited Channel Post handler](#edited-channel-post-handler)
* [Callback Query handlers](#callback-query-handler)
* [Shipping Query Handler](#shipping-query-handler)
* [Pre Checkout Query Handler](#pre-checkout-query-handler)
* [Poll Handler](#poll-handler)
* [Poll Answer Handler](#poll-answer-handler)
* [My Chat Member Handler](#my-chat-member-handler)
* [Chat Member Handler](#chat-member-handler)
* [Chat Join request handler](#chat-join-request-handler)
* [Inline Mode](#inline-mode)
* [Inline handler](#inline-handler)
* [Chosen Inline handler](#chosen-inline-handler)
* [Answer Inline Query](#answer-inline-query)
* [Additional API features](#additional-api-features)
* [Middleware handlers](#middleware-handlers)
* [Custom filters](#custom-filters)
* [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)
* [Using local Bot API Server](#using-local-bot-api-sever)
* [Asynchronous TeleBot](#asynchronous-telebot)
* [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)
* [Testing](#testing)
* [API conformance](#api-conformance)
* [AsyncTeleBot](#asynctelebot)
* [F.A.Q.](#faq)
* [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)
* [How can I handle reocurring ConnectionResetErrors?](#how-can-i-handle-reocurring-connectionreseterrors)
* [The Telegram Chat Group](#the-telegram-chat-group)
* [More examples](#more-examples)
* [Bots using this API](#bots-using-this-api)
## Getting started.
## Getting started
This API is tested with Python 2.6, Python 2.7, Python 3.4, Pypy and Pypy 3.
This API is tested with Python 3.6-3.10 and Pypy 3.
There are two ways to install the library:
* Installation using pip (a Python package manager)*:
@ -69,7 +99,7 @@ Then, open the file and create an instance of the TeleBot class.
```python
import telebot
bot = telebot.TeleBot("TOKEN")
bot = telebot.TeleBot("TOKEN", parse_mode=None) # You can set parse_mode by default. HTML or MARKDOWN
```
*Note: Make sure to actually replace TOKEN with your own API token.*
@ -95,13 +125,13 @@ This one echoes all incoming text messages back to the sender. It uses a lambda
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()
bot.infinity_polling()
```
Alright, that's it! Our source file now looks like this:
```python
import telebot
bot = telebot.TeleBot("TOKEN")
bot = telebot.TeleBot("YOUR_BOT_TOKEN")
@bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
@ -111,7 +141,7 @@ def send_welcome(message):
def echo_all(message):
bot.reply_to(message, message.text)
bot.polling()
bot.infinity_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.
@ -121,8 +151,12 @@ To start the bot, simply open up a terminal and enter `python echo_bot.py` to ru
All types are defined in types.py. They are all completely in line with the [Telegram API's definition of the types](https://core.telegram.org/bots/api#available-types), except for the Message's `from` field, which is renamed to `from_user` (because `from` is a Python reserved token). Thus, attributes such as `message_id` can be accessed directly with `message.message_id`. Note that `message.chat` can be either an instance of `User` or `GroupChat` (see [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)).
The Message object also has a `content_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'.
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_members`, `left_chat_member`, `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`, `supergroup_chat_created`, `channel_chat_created`, `migrate_to_chat_id`, `migrate_from_chat_id`, `pinned_message`.
You can use some types in one function. Example:
```content_types=["text", "sticker", "pinned_message", "photo", "audio"]```
### Methods
@ -134,7 +168,7 @@ 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):
Each filter must 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):
@ -148,11 +182,13 @@ TeleBot supports the following filters:
|name|argument(s)|Condition|
|:---:|---| ---|
|content_types|list of strings (default `['text']`)|`True` if message.content_type is in the list of strings.|
|regexp|a regular expression as a string|`True` if `re.search(regexp_arg)` returns `True` and `message.content_type == 'text'` (See [Python Regular Expressions](https://docs.python.org/2/library/re.html)|
|regexp|a regular expression as a string|`True` if `re.search(regexp_arg)` returns `True` and `message.content_type == 'text'` (See [Python Regular Expressions](https://docs.python.org/2/library/re.html))|
|commands|list of strings|`True` if `message.content_type == 'text'` and `message.text` starts with a command that is in the list of strings.|
|func|a function (lambda or function reference)|`True` if the lambda or function reference returns `True`
|chat_types|list of chat types|`True` if `message.chat.type` in your filter|
|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
bot = telebot.TeleBot("TOKEN")
@ -172,17 +208,17 @@ def handle_docs_audio(message):
def handle_message(message):
pass
#Handles all messages for which the lambda returns True
# Handles all messages for which the lambda returns True
@bot.message_handler(func=lambda message: message.document.mime_type == 'text/plain', content_types=['document'])
def handle_text_doc(message):
pass
#Which could also be defined as:
# Which could also be defined as:
def test_message(message):
return message.document.mime_type == 'text/plan'
return message.document.mime_type == 'text/plain'
@bot.message_handler(func=test_message, content_types=['document'])
def handle_text_doc(message)
def handle_text_doc(message):
pass
# Handlers can be stacked to create a function which will be called if either message_handler is eligible
@ -193,6 +229,158 @@ def send_something(message):
pass
```
**Important: all handlers are tested in the order in which they were declared**
#### Edited Message handler
Handle edited messages
`@bot.edited_message_handler(filters) # <- passes a Message type object to your function`
#### Channel Post handler
Handle channel post messages
`@bot.channel_post_handler(filters) # <- passes a Message type object to your function`
#### Edited Channel Post handler
Handle edited channel post messages
`@bot.edited_channel_post_handler(filters) # <- passes a Message type object to your function`
#### Callback Query Handler
Handle callback queries
```python
@bot.callback_query_handler(func=lambda call: True)
def test_callback(call): # <- passes a CallbackQuery type object to your function
logger.info(call)
```
#### Shipping Query Handler
Handle shipping queries
`@bot.shipping_query_handeler() # <- passes a ShippingQuery type object to your function`
#### Pre Checkout Query Handler
Handle pre checkoupt queries
`@bot.pre_checkout_query_handler() # <- passes a PreCheckoutQuery type object to your function`
#### Poll Handler
Handle poll updates
`@bot.poll_handler() # <- passes a Poll type object to your function`
#### Poll Answer Handler
Handle poll answers
`@bot.poll_answer_handler() # <- passes a PollAnswer type object to your function`
#### My Chat Member Handler
Handle updates of a the bot's member status in a chat
`@bot.my_chat_member_handler() # <- passes a ChatMemberUpdated type object to your function`
#### Chat Member Handler
Handle updates of a chat member's status in a chat
`@bot.chat_member_handler() # <- passes a ChatMemberUpdated type object to your function`
*Note: "chat_member" updates are not requested by default. If you want to allow all update types, set `allowed_updates` in `bot.polling()` / `bot.infinity_polling()` to `util.update_types`*
#### Chat Join Request Handler
Handle chat join requests using:
`@bot.chat_join_request_handler() # <- passes ChatInviteLink type object to your function`
### Inline Mode
More information about [Inline mode](https://core.telegram.org/bots/inline).
#### Inline handler
Now, you can use inline_handler to get inline queries 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)
```
### Additional API features
#### Middleware Handlers
A middleware handler is a function that allows you to modify requests or the bot context as they pass through the
Telegram to the bot. You can imagine middleware as a chain of logic connection handled before any other handlers are
executed. Middleware processing is disabled by default, enable it by setting `apihelper.ENABLE_MIDDLEWARE = True`.
```python
apihelper.ENABLE_MIDDLEWARE = True
@bot.middleware_handler(update_types=['message'])
def modify_message(bot_instance, message):
# modifying the message before it reaches any other handler
message.another_text = message.text + ':changed'
@bot.message_handler(commands=['start'])
def start(message):
# the message is already modified when it reaches message handler
assert message.another_text == message.text + ':changed'
```
There are other examples using middleware handler in the [examples/middleware](examples/middleware) directory.
#### Custom filters
Also, you can use built-in custom filters. Or, you can create your own filter.
[Example of custom filter](https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/custom_filters/general_custom_filters.py)
Also, we have examples on them. Check this links:
You can check some built-in filters in source [code](https://github.com/eternnoir/pyTelegramBotAPI/blob/master/telebot/custom_filters.py)
Example of [filtering by id](https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/custom_filters/id_filter_example.py)
Example of [filtering by text](https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/custom_filters/text_filter_example.py)
If you want to add some built-in filter, you are welcome to add it in custom_filters.py file.
Here is example of creating filter-class:
```python
class IsAdmin(telebot.custom_filters.SimpleCustomFilter):
# Class will check whether the user is admin or creator in group or not
key='is_admin'
@staticmethod
def check(message: telebot.types.Message):
return bot.get_chat_member(message.chat.id,message.from_user.id).status in ['administrator','creator']
# To register filter, you need to use method add_custom_filter.
bot.add_custom_filter(IsAdmin())
# Now, you can use it in handler.
@bot.message_handler(is_admin=True)
def admin_of_group(message):
bot.send_message(message.chat.id, 'You are admin of this group!')
```
#### TeleBot
```python
import telebot
@ -201,11 +389,10 @@ 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
# - block: True/False (default True) - Blocks upon calling this function
tb.polling(none_stop=False, interval=0, block=True)
# - interval: int (default 0) - The interval between polling requests
# - timeout: integer (default 20) - Timeout in seconds for long polling.
# - allowed_updates: List of Strings (default None) - List of update types to request
tb.infinity_polling(interval=0, timeout=20)
# getMe
user = tb.get_me()
@ -217,10 +404,14 @@ tb.remove_webhook()
# getUpdates
updates = tb.get_updates()
# or
updates = tb.get_updates(1234,100,20) #get_Updates(offset, limit, timeout):
# sendMessage
tb.send_message(chatid, text)
tb.send_message(chat_id, text)
# editMessageText
tb.edit_message_text(new_text, chat_id, message_id)
# forwardMessage
tb.forward_message(to_chat_id, from_chat_id, message_id)
@ -259,6 +450,11 @@ 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_note(chat_id, videonote)
tb.send_video_note(chat_id, "FILEID")
# sendLocation
tb.send_location(chat_id, lat, lon)
@ -278,7 +474,7 @@ file = requests.get('https://api.telegram.org/file/bot{0}/{1}'.format(API_TOKEN,
```
#### Reply markup
All `send_xyz` functions of TeleBot take an optional `reply_markup` argument. This argument must be an instance of `ReplyKeyboardMarkup`, `ReplyKeyboardHide` or `ForceReply`, which are defined in types.py.
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
@ -292,23 +488,31 @@ from telebot import types
# 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)
markup.add('a', 'v', 'd')
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')
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://pp.vk.me/c624430/v624430512/473e5/_mxxW7FPe4U.jpg "ReplyKeyboardMarkup")
![ReplyKeyboardMarkup](https://farm3.staticflickr.com/2933/32418726704_9ef76093cf_o_d.jpg "ReplyKeyboardMarkup")
```python
# ReplyKeyboardHide: hides a previously sent ReplyKeyboardMarkup
# ReplyKeyboardRemove: hides a previously sent ReplyKeyboardMarkup
# Takes an optional selective argument (True/False, default False)
markup = types.ReplyKeyboardHide(selective=False)
markup = types.ReplyKeyboardRemove(selective=False)
tb.send_message(chat_id, message, reply_markup=markup)
```
@ -320,57 +524,59 @@ tb.send_message(chat_id, "Send me another word:", reply_markup=markup)
```
ForceReply:
![ForceReply](https://pp.vk.me/c624430/v624430512/473ec/602byyWUHcs.jpg "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).
### 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`
#### 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
```
#### answer_inline_query
```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)
```
**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.
### Using local Bot API Sever
Since version 5.0 of the Bot API, you have the possibility to run your own [Local Bot API Server](https://core.telegram.org/bots/api#using-a-local-bot-api-server).
pyTelegramBotAPI also supports this feature.
```python
from telebot import apihelper
apihelper.API_URL = "http://localhost:4200/bot{0}/{1}"
```
**Important: Like described [here](https://core.telegram.org/bots/api#logout), you have to log out your bot from the Telegram server before switching to your local API server. in pyTelegramBotAPI use `bot.log_out()`**
*Note: 4200 is an example port*
### Asynchronous TeleBot
New: There is an asynchronous implementation of telebot.
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:
Now, every function that calls the Telegram API is executed in a separate asynchronous task.
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
@tb.message_handler(commands=['start'])
async def start_message(message):
await bot.send_message(message.chat.id, 'Hello!')
```
*Note: if you execute send_xyz functions after eachother without calling wait(), the order in which messages are delivered might be wrong.*
See more in [examples](https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples/asynchronous_telebot)
### 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:
@ -381,35 +587,49 @@ 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)
```
Or you can use the new `smart_split` function to get more meaningful substrings:
```python
from telebot import util
large_text = open("large_text.txt", "rb").read()
# Splits one string into multiple strings, with a maximum amount of `chars_per_string` (max. 4096)
# Splits by last '\n', '. ' or ' ' in exactly this priority.
# smart_split returns a list with the splitted text.
splitted_text = util.smart_split(large_text, chars_per_string=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
- threaded: 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:
As an alternative to the message handlers, one can also register a function as a listener to TeleBot.
NOTICE: handlers won't disappear! Your message will be processed both by handlers and listeners. Also, it's impossible to predict which will work at first because of threading. If you use threaded=False, custom listeners will work earlier, after them handlers will be called.
Example:
```python
def handle_messages(messages):
for message in messsages:
for message in messages:
# Do something with the message
bot.reply_to(message, 'Hi')
bot.set_update_listener(handle_messages)
bot.polling()
bot.infinity_polling()
```
### Using webhooks
### 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.
There are some examples using webhooks in the [examples/webhook_examples](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.
@ -420,31 +640,157 @@ logger = telebot.logger
telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console.
```
### Proxy
You can use proxy for request. `apihelper.proxy` object will use by call `requests` proxies argument.
```python
from telebot import apihelper
apihelper.proxy = {'http':'http://127.0.0.1:3128'}
```
If you want to use socket5 proxy you need install dependency `pip install requests[socks]` and make sure, that you have the latest version of `gunicorn`, `PySocks`, `pyTelegramBotAPI`, `requests` and `urllib3`.
```python
apihelper.proxy = {'https':'socks5://userproxy:password@proxy_address:port'}
```
### Testing
You can disable or change the interaction with real Telegram server by using
```python
apihelper.CUSTOM_REQUEST_SENDER = your_handler
```
parameter. You can pass there your own function that will be called instead of _requests.request_.
For example:
```python
def custom_sender(method, url, **kwargs):
print("custom_sender. method: {}, url: {}, params: {}".format(method, url, kwargs.get("params")))
result = util.CustomRequestResponse('{"ok":true,"result":{"message_id": 1, "date": 1, "chat": {"id": 1, "type": "private"}}}')
return result
```
Then you can use API and proceed requests in your handler code.
```python
apihelper.CUSTOM_REQUEST_SENDER = custom_sender
tb = TeleBot("test")
res = tb.send_message(123, "Test")
```
Result will be:
`custom_sender. method: post, url: https://api.telegram.org/botololo/sendMessage, params: {'chat_id': '123', 'text': 'Test'}`
## API conformance
* ✔ [Bot API 5.4](https://core.telegram.org/bots/api#november-5-2021)
* [Bot API 5.3](https://core.telegram.org/bots/api#june-25-2021) - ChatMemberXXX classes are full copies of ChatMember
* ✔ [Bot API 5.2](https://core.telegram.org/bots/api#april-26-2021)
* ✔ [Bot API 5.1](https://core.telegram.org/bots/api#march-9-2021)
* ✔ [Bot API 5.0](https://core.telegram.org/bots/api-changelog#november-4-2020)
* ✔ [Bot API 4.9](https://core.telegram.org/bots/api-changelog#june-4-2020)
* ✔ [Bot API 4.8](https://core.telegram.org/bots/api-changelog#april-24-2020)
* ✔ [Bot API 4.7](https://core.telegram.org/bots/api-changelog#march-30-2020)
* ✔ [Bot API 4.6](https://core.telegram.org/bots/api-changelog#january-23-2020)
* [Bot API 4.5](https://core.telegram.org/bots/api-changelog#december-31-2019) - No nested MessageEntities and Markdown2 support
* ✔ [Bot API 4.4](https://core.telegram.org/bots/api-changelog#july-29-2019)
* ✔ [Bot API 4.3](https://core.telegram.org/bots/api-changelog#may-31-2019)
* ✔ [Bot API 4.2](https://core.telegram.org/bots/api-changelog#april-14-2019)
* [Bot API 4.1](https://core.telegram.org/bots/api-changelog#august-27-2018) - No Passport support
* [Bot API 4.0](https://core.telegram.org/bots/api-changelog#july-26-2018) - No Passport support
* ✔ [Bot API 3.6](https://core.telegram.org/bots/api-changelog#february-13-2018)
* ✔ [Bot API 3.5](https://core.telegram.org/bots/api-changelog#november-17-2017)
* ✔ [Bot API 3.4](https://core.telegram.org/bots/api-changelog#october-11-2017)
* ✔ [Bot API 3.3](https://core.telegram.org/bots/api-changelog#august-23-2017)
* ✔ [Bot API 3.2](https://core.telegram.org/bots/api-changelog#july-21-2017)
* ✔ [Bot API 3.1](https://core.telegram.org/bots/api-changelog#june-30-2017)
* ✔ [Bot API 3.0](https://core.telegram.org/bots/api-changelog#may-18-2017)
* ✔ [Bot API 2.3.1](https://core.telegram.org/bots/api-changelog#december-4-2016)
* ✔ [Bot API 2.3](https://core.telegram.org/bots/api-changelog#november-21-2016)
* ✔ [Bot API 2.2](https://core.telegram.org/bots/api-changelog#october-3-2016)
* ✔ [Bot API 2.1](https://core.telegram.org/bots/api-changelog#may-22-2016)
* ✔ [Bot API 2.0](https://core.telegram.org/bots/api-changelog#april-9-2016)
## AsyncTeleBot
### Asynchronous version of telebot
We have a fully asynchronous version of TeleBot.
This class is not controlled by threads. Asyncio tasks are created to execute all the stuff.
### EchoBot
Echo Bot example on AsyncTeleBot:
```python
# This is a simple echo bot using the decorator mechanism.
# It echoes any incoming text messages.
from telebot.async_telebot import AsyncTeleBot
bot = AsyncTeleBot('TOKEN')
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
async def send_welcome(message):
await bot.reply_to(message, """\
Hi there, I am EchoBot.
I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\
""")
# Handle all other messages with content_type 'text' (content_types defaults to ['text'])
@bot.message_handler(func=lambda message: True)
async def echo_message(message):
await bot.reply_to(message, message.text)
bot.polling()
```
As you can see here, keywords are await and async.
### Why should I use async?
Asynchronous tasks depend on processor performance. Many asynchronous tasks can run parallelly, while thread tasks will block each other.
### Differences in AsyncTeleBot
AsyncTeleBot has different middlewares. See example on [middlewares](https://github.com/coder2020official/pyTelegramBotAPI/tree/master/examples/asynchronous_telebot/middleware)
### Examples
See more examples in our [examples](https://github.com/coder2020official/pyTelegramBotAPI/tree/master/examples/asynchronous_telebot) folder
## F.A.Q.
### 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 == "private":
# private chat message
if message.chat.type == group:
if message.chat.type == "group":
# group chat message
if message.chat.type == channel:
if message.chat.type == "supergroup":
# supergroup chat message
if message.chat.type == "channel":
# channel message
```
### How can I handle reocurring ConnectionResetErrors?
Bot instances that were idle for a long time might be rejected by the server when sending a message due to a timeout of the last used session. Add `apihelper.SESSION_TIME_TO_LIVE = 5 * 60` to your initialisation to force recreation after 5 minutes without any activity.
## 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).
* Join the [pyTelegramBotAPI Telegram Chat Group](https://telegram.me/joinchat/Bn4ixj84FIZVkwhk2jag6A)
## More examples
@ -454,4 +800,50 @@ Get help. Discuss. Chat.
## 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
Want to have your bot listed here? Send a Telegram message to @eternnoir or @pevdh.
* [TelegramLoggingBot](https://github.com/aRandomStranger/TelegramLoggingBot) by *aRandomStranger*
* [Telegram LMGTFY_bot](https://github.com/GabrielRF/telegram-lmgtfy_bot) by *GabrielRF* - Let me Google that for you.
* [Telegram Proxy Bot](https://github.com/mrgigabyte/proxybot) by *mrgigabyte*
* [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](https://github.com/neoranger)
* [ColorCodeBot](https://t.me/colorcodebot) ([source](https://github.com/andydecleyre/colorcodebot)) - Share code snippets as beautifully syntax-highlighted HTML and/or images.
* [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.
* [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.
* [wat-bridge](https://github.com/rmed/wat-bridge) by [*rmed*](https://github.com/rmed) - Send and receive messages to/from WhatsApp through Telegram
* [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
* [Send2Kindlebot](http://t.me/Send2KindleBot) ([source](https://github.com/GabrielRF/Send2KindleBot)) by *GabrielRF* - Send to Kindle service.
* [RastreioBot](http://t.me/RastreioBot) ([source](https://github.com/GabrielRF/RastreioBot)) by *GabrielRF* - Bot used to track packages on the Brazilian Mail Service.
* [Spbu4UBot](http://t.me/Spbu4UBot)([link](https://github.com/EeOneDown/spbu4u)) by *EeOneDown* - Bot with timetables for SPbU students.
* [SmartySBot](http://t.me/ZDU_bot)([link](https://github.com/0xVK/SmartySBot)) by *0xVK* - Telegram timetable bot, for Zhytomyr Ivan Franko State University students.
* [LearnIt](https://t.me/LearnItbot)([link](https://github.com/tiagonapoli/LearnIt)) - A Telegram Bot created to help people to memorize other languages vocabulary.
* [Bot-Telegram-Shodan ](https://github.com/rubenleon/Bot-Telegram-Shodan) by [rubenleon](https://github.com/rubenleon)
* [VigoBusTelegramBot](https://t.me/vigobusbot) ([GitHub](https://github.com/Pythoneiro/VigoBus-TelegramBot)) - Bot that provides buses coming to a certain stop and their remaining time for the city of Vigo (Galicia - Spain)
* [kaishnik-bot](https://t.me/kaishnik_bot) ([source](https://github.com/airatk/kaishnik-bot)) by *airatk* - bot which shows all the necessary information to KNTRU-KAI students.
* [Robbie](https://t.me/romdeliverybot) ([source](https://github.com/FacuM/romdeliverybot_support)) by @FacuM - Support Telegram bot for developers and maintainers.
* [AsadovBot](https://t.me/asadov_bot) ([source](https://github.com/desexcile/BotApi)) by @DesExcile - Сatalog of poems by Eduard Asadov.
* [thesaurus_com_bot](https://t.me/thesaurus_com_bot) ([source](https://github.com/LeoSvalov/words-i-learn-bot)) by @LeoSvalov - words and synonyms from [dictionary.com](https://www.dictionary.com) and [thesaurus.com](https://www.thesaurus.com) in the telegram.
* [InfoBot](https://t.me/info2019_bot) ([source](https://github.com/irevenko/info-bot)) by @irevenko - An all-round bot that displays some statistics (weather, time, crypto etc...)
* [FoodBot](https://t.me/ChensonUz_bot) ([source](https://github.com/Fliego/old_restaurant_telegram_chatbot)) by @Fliego - a simple bot for food ordering
* [Sporty](https://t.me/SportydBot) ([source](https://github.com/0xnu/sporty)) by @0xnu - Telegram bot for displaying the latest news, sports schedules and injury updates.
* [JoinGroup Silencer Bot](https://t.me/joingroup_silencer_bot) ([source](https://github.com/zeph1997/Telegram-Group-Silencer-Bot)) by [@zeph1997](https://github.com/zeph1997) - A Telegram Bot to remove "join group" and "removed from group" notifications.
* [TasksListsBot](https://t.me/TasksListsBot) ([source](https://github.com/Pablo-Davila/TasksListsBot)) by [@Pablo-Davila](https://github.com/Pablo-Davila) - A (tasks) lists manager bot for Telegram.
* [MyElizaPsychologistBot](https://t.me/TasksListsBot) ([source](https://github.com/Pablo-Davila/MyElizaPsychologistBot)) by [@Pablo-Davila](https://github.com/Pablo-Davila) - An implementation of the famous Eliza psychologist chatbot.
* [Frcstbot](https://t.me/frcstbot) ([source](https://github.com/Mrsqd/frcstbot_public)) by [Mrsqd](https://github.com/Mrsqd). A Telegram bot that will always be happy to show you the weather forecast.
* [MineGramBot](https://github.com/ModischFabrications/MineGramBot) by [ModischFabrications](https://github.com/ModischFabrications). This bot can start, stop and monitor a minecraft server.
* [Tabletop DiceBot](https://github.com/dexpiper/tabletopdicebot) by [dexpiper](https://github.com/dexpiper). This bot can roll multiple dices for RPG-like games, add positive and negative modifiers and show short descriptions to the rolls.
* [BarnameKon](https://t.me/BarnameKonBot) by [Anvaari](https://github.com/anvaari). This Bot make "Add to google calendar" link for your events. It give information about event and return link. It work for Jalali calendar and in Tehran Time. [Source code](https://github.com/anvaari/BarnameKon)
* [Translator bot](https://github.com/AREEG94FAHAD/translate_text_bot) by Areeg Fahad. This bot can be used to translate texts.
* [Digital Cryptocurrency bot](https://github.com/AREEG94FAHAD/currencies_bot) by Areeg Fahad. With this bot, you can now monitor the prices of more than 12 digital Cryptocurrency.
* [Anti-Tracking Bot](https://t.me/AntiTrackingBot) by Leon Heess [(source)](https://github.com/leonheess/AntiTrackingBot). Send any link, and the bot tries its best to remove all tracking from the link you sent.
* [Developer Bot](https://t.me/IndDeveloper_bot) by [Vishal Singh](https://github.com/vishal2376) [(source code)](https://github.com/vishal2376/telegram-bot) This telegram bot can do tasks like GitHub search & clone,provide c++ learning resources ,Stackoverflow search, Codeforces(profile visualizer,random problems)
* [oneIPO bot](https://github.com/aaditya2200/IPO-proj) by [Aadithya](https://github.com/aaditya2200) & [Amol Soans](https://github.com/AmolDerickSoans) This Telegram bot provides live updates , data and documents on current and upcoming IPOs(Initial Public Offerings)
* [CoronaGraphsBot](https://t.me/CovidGraph_bot) ([source](https://github.com/TrevorWinstral/CoronaGraphsBot)) by *TrevorWinstral* - Gets live COVID Country data, plots it, and briefs the user
* [ETHLectureBot](https://t.me/ETHLectureBot) ([source](https://github.com/TrevorWinstral/ETHLectureBot)) by *TrevorWinstral* - Notifies ETH students when their lectures have been uploaded
* [Vlun Finder Bot](https://github.com/resinprotein2333/Vlun-Finder-bot) by [Resinprotein2333](https://github.com/resinprotein2333). This bot can help you to find The information of CVE vulnerabilities.
* [ETHGasFeeTrackerBot](https://t.me/ETHGasFeeTrackerBot) ([Source](https://github.com/DevAdvik/ETHGasFeeTrackerBot]) by *DevAdvik* - Get Live Ethereum Gas Fees in GWEI
* [Google Sheet Bot](https://github.com/JoachimStanislaus/Tele_Sheet_bot) by [JoachimStanislaus](https://github.com/JoachimStanislaus). This bot can help you to track your expenses by uploading your bot entries to your google sheet.
* [GrandQuiz Bot](https://github.com/Carlosma7/TFM-GrandQuiz) by [Carlosma7](https://github.com/Carlosma7). This bot is a trivia game that allows you to play with people from different ages. This project addresses the use of a system through chatbots to carry out a social and intergenerational game as an alternative to traditional game development.
**Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.**

View File

@ -1,592 +0,0 @@
#
.. raw:: html
<p align="center">
pyTelegramBotAPI
.. raw:: html
<p align="center">
A simple, but extensible Python implementation for the `Telegram Bot
API <https://core.telegram.org/bots/api>`__.
.. raw:: html
<p align="center">
|Build Status|
- `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>`__
- `TeleBot <#telebot>`__
- `Reply markup <#reply-markup>`__
- `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>`__
- `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_type``\ attribute, which defines
the type of the Message. ``content_type`` can be one of the following
strings: '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'.
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 | 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:
.. 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** #### 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
# - block: True/False (default True) - Blocks upon calling this function
tb.polling(none_stop=False, interval=0, block=True)
# 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``,
``ReplyKeyboardHide`` 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)
markup.add('a', 'v', 'd')
tb.send_message(chat_id, "Choose one letter:", reply_markup=markup)
# or add strings one row at a time:
markup = types.ReplyKeyboardMarkup()
markup.row('a', 'v')
markup.row('c', 'd', 'e')
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
# ReplyKeyboardHide: hides a previously sent ReplyKeyboardMarkup
# Takes an optional selective argument (True/False, default False)
markup = types.ReplyKeyboardHide(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
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.
======
How can I distinguish a User and a GroupChat in message.chat?
-------------------------------------------------------------
There are two ways to do this:
- Checking the instance of message.chat with ``isinstance``:
\`\`\`python def is\_user(chat): return isinstance(chat, types.User)
print is\_user(message.chat) # True or False
``- Checking whether the chat id is negative or positive. If the chat id is negative, the chat is a GroupChat, if it is positive, it is a User. Example:``\ python
def is\_user(chat): return chat.id > 0
print is\_user(message.chat) # True or False \`\`\`
The Telegram Chat Group
=======================
Get help. Discuss. Chat.
Join the `pyTelegramBotAPI Telegram Chat
Group <https://telegram.me/joinchat/067e22c60035523fda8f6025ee87e30b>`__.
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
Want to have your bot listed here? Send a Telegram message to
@eternnoir or @pevdh.
.. |Build Status| image:: https://travis-ci.org/eternnoir/pyTelegramBotAPI.svg?branch=master
:target: https://travis-ci.org/eternnoir/pyTelegramBotAPI

View File

@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
"""
This Example will show you how to use CallbackData
"""
from telebot.callback_data import CallbackData, CallbackDataFilter
from telebot import types, TeleBot
from telebot.custom_filters import AdvancedCustomFilter
API_TOKEN = ''
PRODUCTS = [
{'id': '0', 'name': 'xiaomi mi 10', 'price': 400},
{'id': '1', 'name': 'samsung s20', 'price': 800},
{'id': '2', 'name': 'iphone 13', 'price': 1300}
]
bot = TeleBot(API_TOKEN)
products_factory = CallbackData('product_id', prefix='products')
def products_keyboard():
return types.InlineKeyboardMarkup(
keyboard=[
[
types.InlineKeyboardButton(
text=product['name'],
callback_data=products_factory.new(product_id=product["id"])
)
]
for product in PRODUCTS
]
)
def back_keyboard():
return types.InlineKeyboardMarkup(
keyboard=[
[
types.InlineKeyboardButton(
text='',
callback_data='back'
)
]
]
)
class ProductsCallbackFilter(AdvancedCustomFilter):
key = 'config'
def check(self, call: types.CallbackQuery, config: CallbackDataFilter):
return config.check(query=call)
@bot.message_handler(commands=['products'])
def products_command_handler(message: types.Message):
bot.send_message(message.chat.id, 'Products:', reply_markup=products_keyboard())
# Only product with field - product_id = 2
@bot.callback_query_handler(func=None, config=products_factory.filter(product_id='2'))
def product_one_callback(call: types.CallbackQuery):
bot.answer_callback_query(callback_query_id=call.id, text='Not available :(', show_alert=True)
# Any other products
@bot.callback_query_handler(func=None, config=products_factory.filter())
def products_callback(call: types.CallbackQuery):
callback_data: dict = products_factory.parse(callback_data=call.data)
product_id = int(callback_data['product_id'])
product = PRODUCTS[product_id]
text = f"Product name: {product['name']}\n" \
f"Product price: {product['price']}"
bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id,
text=text, reply_markup=back_keyboard())
@bot.callback_query_handler(func=lambda c: c.data == 'back')
def back_callback(call: types.CallbackQuery):
bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id,
text='Products:', reply_markup=products_keyboard())
bot.add_custom_filter(ProductsCallbackFilter())
bot.infinity_polling()

117
examples/anonymous_bot.py Normal file
View File

@ -0,0 +1,117 @@
# This bot is needed to connect two people and their subsequent anonymous communication
#
# Avaiable commands:
# `/start` - Just send you a messsage how to start
# `/find` - Find a person you can contact
# `/stop` - Stop active conversation
import telebot
from telebot import types
# Initialize bot with your token
bot = telebot.TeleBot(TOKEN)
# The `users` variable is needed to contain chat ids that are either in the search or in the active dialog, like {chat_id, chat_id}
users = {}
# The `freeid` variable is needed to contain chat id, that want to start conversation
# Or, in other words: chat id of user in the search
freeid = None
# `/start` command handler
#
# That command only sends you 'Just use /find command!'
@bot.message_handler(commands=['start'])
def start(message: types.Message):
bot.send_message(message.chat.id, 'Just use /find command!')
# `/find` command handler
#
# That command finds opponent for you
#
# That command according to the following principle:
# 1. You have written `/find` command
# 2. If you are already in the search or have an active dialog, bot sends you 'Shut up!'
# 3. If not:
# 3.1. Bot sends you 'Finding...'
# 3.2. If there is no user in the search:
# 3.2.2. `freeid` updated with `your_chat_id`
# 3.3. If there is user in the search:
# 3.3.1. Both you and the user in the search recieve the message 'Founded!'
# 3.3.2. `users` updated with a {user_in_the_search_chat_id, your_chat_id}
# 3.3.3. `users` updated with a {your_chat_id, user_in_the_search_id}
# 3.3.4. `freeid` updated with `None`
@bot.message_handler(commands=['find'])
def find(message: types.Message):
global freeid
if message.chat.id not in users:
bot.send_message(message.chat.id, 'Finding...')
if freeid == None:
freeid = message.chat.id
else:
# Question:
# Is there any way to simplify this like `bot.send_message([message.chat.id, freeid], 'Founded!')`?
bot.send_message(message.chat.id, 'Founded!')
bot.send_message(freeid, 'Founded!')
users[freeid] = message.chat.id
users[message.chat.id] = freeid
freeid = None
print(users, freeid) # Debug purpose, you can remove that line
else:
bot.send_message(message.chat.id, 'Shut up!')
# `/stop` command handler
#
# That command stops your current conversation (if it exist)
#
# That command according to the following principle:
# 1. You have written `/stop` command
# 2. If you are not have active dialog or you are not in search, bot sends you 'You are not in search!'
# 3. If you are in active dialog:
# 3.1. Bot sends you 'Stopping...'
# 3.2. Bot sends 'Your opponent is leavin`...' to your opponent
# 3.3. {your_opponent_chat_id, your_chat_id} removes from `users`
# 3.4. {your_chat_id, your_opponent_chat_id} removes from `users`
# 4. If you are only in search:
# 4.1. Bot sends you 'Stopping...'
# 4.2. `freeid` updated with `None`
@bot.message_handler(commands=['stop'])
def stop(message: types.Message):
global freeid
if message.chat.id in users:
bot.send_message(message.chat.id, 'Stopping...')
bot.send_message(users[message.chat.id], 'Your opponent is leavin`...')
del users[users[message.chat.id]]
del users[message.chat.id]
print(users, freeid) # Debug purpose, you can remove that line
elif message.chat.id == freeid:
bot.send_message(message.chat.id, 'Stopping...')
freeid = None
print(users, freeid) # Debug purpose, you can remove that line
else:
bot.send_message(message.chat.id, 'You are not in search!')
# message handler for conversation
#
# That handler needed to send message from one opponent to another
# If you are not in `users`, you will recieve a message 'No one can hear you...'
# Otherwise all your messages are sent to your opponent
#
# Questions:
# 1. Is there any way to improve readability like `content_types=['all']`?
# 2. Is there any way to register this message handler only when i found the opponent?
@bot.message_handler(content_types=['animation', 'audio', 'contact', 'dice', 'document', 'location', 'photo', 'poll', 'sticker', 'text', 'venue', 'video', 'video_note', 'voice'])
def chatting(message: types.Message):
if message.chat.id in users:
bot.copy_message(users[message.chat.id], users[users[message.chat.id]], message.id)
else:
bot.send_message(message.chat.id, 'No one can hear you...')
bot.infinity_polling(skip_pending=True)

View File

@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
"""
This Example will show you how to use CallbackData
"""
from telebot.callback_data import CallbackData, CallbackDataFilter
from telebot import types
from telebot.async_telebot import AsyncTeleBot
from telebot.asyncio_filters import AdvancedCustomFilter
API_TOKEN = 'TOKEN'
PRODUCTS = [
{'id': '0', 'name': 'xiaomi mi 10', 'price': 400},
{'id': '1', 'name': 'samsung s20', 'price': 800},
{'id': '2', 'name': 'iphone 13', 'price': 1300}
]
bot = AsyncTeleBot(API_TOKEN)
products_factory = CallbackData('product_id', prefix='products')
def products_keyboard():
return types.InlineKeyboardMarkup(
keyboard=[
[
types.InlineKeyboardButton(
text=product['name'],
callback_data=products_factory.new(product_id=product["id"])
)
]
for product in PRODUCTS
]
)
def back_keyboard():
return types.InlineKeyboardMarkup(
keyboard=[
[
types.InlineKeyboardButton(
text='',
callback_data='back'
)
]
]
)
class ProductsCallbackFilter(AdvancedCustomFilter):
key = 'config'
async def check(self, call: types.CallbackQuery, config: CallbackDataFilter):
return config.check(query=call)
@bot.message_handler(commands=['products'])
async def products_command_handler(message: types.Message):
await bot.send_message(message.chat.id, 'Products:', reply_markup=products_keyboard())
# Only product with field - product_id = 2
@bot.callback_query_handler(func=None, config=products_factory.filter(product_id='2'))
async def product_one_callback(call: types.CallbackQuery):
await bot.answer_callback_query(callback_query_id=call.id, text='Not available :(', show_alert=True)
# Any other products
@bot.callback_query_handler(func=None, config=products_factory.filter())
async def products_callback(call: types.CallbackQuery):
callback_data: dict = products_factory.parse(callback_data=call.data)
product_id = int(callback_data['product_id'])
product = PRODUCTS[product_id]
text = f"Product name: {product['name']}\n" \
f"Product price: {product['price']}"
await bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id,
text=text, reply_markup=back_keyboard())
@bot.callback_query_handler(func=lambda c: c.data == 'back')
async def back_callback(call: types.CallbackQuery):
await bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id,
text='Products:', reply_markup=products_keyboard())
bot.add_custom_filter(ProductsCallbackFilter())
bot.polling()

View File

@ -0,0 +1,11 @@
from telebot.async_telebot import AsyncTeleBot
import telebot
bot = AsyncTeleBot('TOKEN')
@bot.chat_join_request_handler()
async def make_some(message: telebot.types.ChatJoinRequest):
await bot.send_message(message.chat.id, 'I accepted a new user!')
await bot.approve_chat_join_request(message.chat.id, message.from_user.id)
bot.polling(skip_pending=True)

View File

@ -0,0 +1,33 @@
from telebot import types,util
from telebot.async_telebot import AsyncTeleBot
bot = AsyncTeleBot('TOKEN')
#chat_member_handler. When status changes, telegram gives update. check status from old_chat_member and new_chat_member.
@bot.chat_member_handler()
async def chat_m(message: types.ChatMemberUpdated):
old = message.old_chat_member
new = message.new_chat_member
if new.status == "member":
await bot.send_message(message.chat.id,"Hello {name}!".format(name=new.user.first_name)) # Welcome message
#if bot is added to group, this handler will work
@bot.my_chat_member_handler()
async def my_chat_m(message: types.ChatMemberUpdated):
old = message.old_chat_member
new = message.new_chat_member
if new.status == "member":
await bot.send_message(message.chat.id,"Somebody added me to group") # Welcome message, if bot was added to group
await bot.leave_chat(message.chat.id)
#content_Type_service is:
#'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created',
#'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message',
#'proximity_alert_triggered', 'voice_chat_scheduled', 'voice_chat_started', 'voice_chat_ended',
#'voice_chat_participants_invited', 'message_auto_delete_timer_changed'
# this handler deletes service messages
@bot.message_handler(content_types=util.content_type_service)
async def delall(message: types.Message):
await bot.delete_message(message.chat.id,message.message_id)
bot.polling()

View File

@ -0,0 +1,12 @@
from telebot.async_telebot import AsyncTeleBot
from telebot import asyncio_filters
bot = AsyncTeleBot('TOKEN')
# Handler
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True)
async def answer_for_admin(message):
await bot.send_message(message.chat.id,"hello my admin")
# Register filter
bot.add_custom_filter(asyncio_filters.IsAdminFilter(bot))
bot.polling()

View File

@ -0,0 +1,43 @@
from telebot.async_telebot import AsyncTeleBot
import telebot
bot = AsyncTeleBot('TOKEN')
# AdvancedCustomFilter is for list, string filter values
class MainFilter(telebot.asyncio_filters.AdvancedCustomFilter):
key='text'
@staticmethod
async def check(message, text):
return message.text in text
# SimpleCustomFilter is for boolean values, such as is_admin=True
class IsAdmin(telebot.asyncio_filters.SimpleCustomFilter):
key='is_admin'
@staticmethod
async def check(message: telebot.types.Message):
result = await bot.get_chat_member(message.chat.id,message.from_user.id)
return result.status in ['administrator','creator']
@bot.message_handler(is_admin=True, commands=['admin']) # Check if user is admin
async def admin_rep(message):
await bot.send_message(message.chat.id, "Hi admin")
@bot.message_handler(is_admin=False, commands=['admin']) # If user is not admin
async def not_admin(message):
await bot.send_message(message.chat.id, "You are not admin")
@bot.message_handler(text=['hi']) # Response to hi message
async def welcome_hi(message):
await bot.send_message(message.chat.id, 'You said hi')
@bot.message_handler(text=['bye']) # Response to bye message
async def bye_user(message):
await bot.send_message(message.chat.id, 'You said bye')
# Do not forget to register filters
bot.add_custom_filter(MainFilter())
bot.add_custom_filter(IsAdmin())
bot.polling()

View File

@ -0,0 +1,17 @@
from telebot.async_telebot import AsyncTeleBot
import telebot
bot = AsyncTeleBot('TOKEN')
# Chat id can be private or supergroups.
@bot.message_handler(chat_id=[12345678], commands=['admin']) # chat_id checks id corresponds to your list or not.
async def admin_rep(message):
await bot.send_message(message.chat.id, "You are allowed to use this command.")
@bot.message_handler(commands=['admin'])
async def not_admin(message):
await bot.send_message(message.chat.id, "You are not allowed to use this command")
# Do not forget to register
bot.add_custom_filter(telebot.asyncio_filters.ChatFilter())
bot.polling()

View File

@ -0,0 +1,22 @@
from telebot.async_telebot import AsyncTeleBot
import telebot
bot = AsyncTeleBot('TOKEN')
# Check if message is a reply
@bot.message_handler(is_reply=True)
async def start_filter(message):
await bot.send_message(message.chat.id, "Looks like you replied to my message.")
# Check if message was forwarded
@bot.message_handler(is_forwarded=True)
async def text_filter(message):
await bot.send_message(message.chat.id, "I do not accept forwarded messages!")
# Do not forget to register filters
bot.add_custom_filter(telebot.asyncio_filters.IsReplyFilter())
bot.add_custom_filter(telebot.asyncio_filters.ForwardFilter())
bot.polling()

View File

@ -0,0 +1,20 @@
from telebot.async_telebot import AsyncTeleBot
import telebot
bot = AsyncTeleBot('TOKEN')
# Check if message starts with @admin tag
@bot.message_handler(text_startswith="@admin")
async def start_filter(message):
await bot.send_message(message.chat.id, "Looks like you are calling admin, wait...")
# Check if text is hi or hello
@bot.message_handler(text=['hi','hello'])
async def text_filter(message):
await bot.send_message(message.chat.id, "Hi, {name}!".format(name=message.from_user.first_name))
# Do not forget to register filters
bot.add_custom_filter(telebot.asyncio_filters.TextMatchFilter())
bot.add_custom_filter(telebot.asyncio_filters.TextStartsFilter())
bot.polling()

View File

@ -0,0 +1,74 @@
import telebot
from telebot import asyncio_filters
from telebot.async_telebot import AsyncTeleBot
bot = AsyncTeleBot('TOKEN')
class MyStates:
name = 1
surname = 2
age = 3
@bot.message_handler(commands=['start'])
async def start_ex(message):
"""
Start command. Here we are starting state
"""
await bot.set_state(message.from_user.id, MyStates.name)
await bot.send_message(message.chat.id, 'Hi, write me a name')
@bot.message_handler(state="*", commands='cancel')
async def any_state(message):
"""
Cancel state
"""
await bot.send_message(message.chat.id, "Your state was cancelled.")
await bot.delete_state(message.from_user.id)
@bot.message_handler(state=MyStates.name)
async def name_get(message):
"""
State 1. Will process when user's state is 1.
"""
await bot.send_message(message.chat.id, f'Now write me a surname')
await bot.set_state(message.from_user.id, MyStates.surname)
async with bot.retrieve_data(message.from_user.id) as data:
data['name'] = message.text
@bot.message_handler(state=MyStates.surname)
async def ask_age(message):
"""
State 2. Will process when user's state is 2.
"""
await bot.send_message(message.chat.id, "What is your age?")
await bot.set_state(message.from_user.id, MyStates.age)
async with bot.retrieve_data(message.from_user.id) as data:
data['surname'] = message.text
# result
@bot.message_handler(state=MyStates.age, is_digit=True)
async def ready_for_answer(message):
async with bot.retrieve_data(message.from_user.id) as data:
await bot.send_message(message.chat.id, "Ready, take a look:\n<b>Name: {name}\nSurname: {surname}\nAge: {age}</b>".format(name=data['name'], surname=data['surname'], age=message.text), parse_mode="html")
await bot.delete_state(message.from_user.id)
#incorrect number
@bot.message_handler(state=MyStates.age, is_digit=False)
async def age_incorrect(message):
await bot.send_message(message.chat.id, 'Looks like you are submitting a string in the field age. Please enter a number')
# register filters
bot.add_custom_filter(asyncio_filters.StateFilter(bot))
bot.add_custom_filter(asyncio_filters.IsDigitFilter())
# set saving states into file.
bot.enable_saving_states() # you can delete this if you do not need to save states
bot.polling()

View File

@ -0,0 +1,20 @@
import telebot
from telebot.async_telebot import AsyncTeleBot
bot = AsyncTeleBot('TOKEN')
@bot.message_handler(content_types=['photo'])
async def new_message(message: telebot.types.Message):
result_message = await bot.send_message(message.chat.id, '<i>Downloading your photo...</i>', parse_mode='HTML', disable_web_page_preview=True)
file_path = await bot.get_file(message.photo[-1].file_id)
downloaded_file = await bot.download_file(file_path.file_path)
with open('file.jpg', 'wb') as new_file:
new_file.write(downloaded_file)
await bot.edit_message_text(chat_id=message.chat.id, message_id=result_message.id, text='<i>Done!</i>', parse_mode='HTML')
bot.polling(skip_pending=True)

View File

@ -0,0 +1,26 @@
#!/usr/bin/python
# This is a simple echo bot using the decorator mechanism.
# It echoes any incoming text messages.
from telebot.async_telebot import AsyncTeleBot
bot = AsyncTeleBot('TOKEN')
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
async def send_welcome(message):
await bot.reply_to(message, """\
Hi there, I am EchoBot.
I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\
""")
# Handle all other messages with content_type 'text' (content_types defaults to ['text'])
@bot.message_handler(func=lambda message: True)
async def echo_message(message):
await bot.reply_to(message, message.text)
bot.polling()

View File

@ -0,0 +1,27 @@
import telebot
from telebot.async_telebot import AsyncTeleBot
import logging
logger = telebot.logger
telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console.
class ExceptionHandler(telebot.ExceptionHandler):
def handle(self, exception):
logger.error(exception)
bot = AsyncTeleBot('TOKEN',exception_handler=ExceptionHandler())
@bot.message_handler(commands=['photo'])
async def photo_send(message: telebot.types.Message):
await bot.send_message(message.chat.id, 'Hi, this is an example of exception handlers.')
raise Exception('test') # Exception goes to ExceptionHandler if it is set
bot.polling(skip_pending=True)

View File

@ -0,0 +1,39 @@
# Just a little example of middleware handlers
import telebot
from telebot.asyncio_handler_backends import BaseMiddleware
from telebot.async_telebot import AsyncTeleBot
from telebot.async_telebot import CancelUpdate
bot = AsyncTeleBot('TOKEN')
class SimpleMiddleware(BaseMiddleware):
def __init__(self, limit) -> None:
self.last_time = {}
self.limit = limit
self.update_types = ['message']
# Always specify update types, otherwise middlewares won't work
async def pre_process(self, message, data):
if not message.from_user.id in self.last_time:
# User is not in a dict, so lets add and cancel this function
self.last_time[message.from_user.id] = message.date
return
if message.date - self.last_time[message.from_user.id] < self.limit:
# User is flooding
await bot.send_message(message.chat.id, 'You are making request too often')
return CancelUpdate()
self.last_time[message.from_user.id] = message.date
async def post_process(self, message, data, exception):
pass
bot.setup_middleware(SimpleMiddleware(2))
@bot.message_handler(commands=['start'])
async def start(message):
await bot.send_message(message.chat.id, 'Hello!')
bot.polling()

View File

@ -0,0 +1,48 @@
#!/usr/bin/python
# This example shows how to implement i18n (internationalization) l10n (localization) to create
# multi-language bots with middleware handler.
#
# Also, you could check language code in handler itself too.
# But this example just to show the work of middlewares.
import telebot
from telebot.async_telebot import AsyncTeleBot
from telebot import asyncio_handler_backends
import logging
logger = telebot.logger
telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console.
TRANSLATIONS = {
'hello': {
'en': 'hello',
'ru': 'привет',
'uz': 'salom'
}
}
bot = AsyncTeleBot('TOKEN')
class LanguageMiddleware(asyncio_handler_backends.BaseMiddleware):
def __init__(self):
self.update_types = ['message'] # Update types that will be handled by this middleware.
async def pre_process(self, message, data):
data['response'] = TRANSLATIONS['hello'][message.from_user.language_code]
async def post_process(self, message, data, exception):
if exception: # You can get exception occured in handler.
logger.exception(str(exception))
bot.setup_middleware(LanguageMiddleware()) # do not forget to setup
@bot.message_handler(commands=['start'])
async def start(message, data: dict):
# you can get the data in handler too.
# Not necessary to create data parameter in handler function.
await bot.send_message(message.chat.id, data['response'])
bot.polling()

View File

@ -0,0 +1,18 @@
from telebot.async_telebot import AsyncTeleBot
bot = AsyncTeleBot('TOKEN')
async def start_executor(message):
await bot.send_message(message.chat.id, 'Hello!')
bot.register_message_handler(start_executor, commands=['start']) # Start command executor
# See also
# bot.register_callback_query_handler(*args, **kwargs)
# bot.register_channel_post_handler(*args, **kwargs)
# bot.register_chat_member_handler(*args, **kwargs)
# bot.register_inline_handler(*args, **kwargs)
# bot.register_my_chat_member_handler(*args, **kwargs)
# bot.register_edited_message_handler(*args, **kwargs)
# And other functions..
bot.polling(skip_pending=True)

View File

@ -0,0 +1,27 @@
import telebot
from telebot.async_telebot import AsyncTeleBot
bot = AsyncTeleBot('TOKEN')
@bot.message_handler(commands=['photo'])
async def photo_send(message: telebot.types.Message):
with open('test.png', 'rb') as new_file:
await bot.send_photo(message.chat.id, new_file)
@bot.message_handler(commands=['document'])
async def document_send(message: telebot.types.Message):
with open('test.docx', 'rb') as new_file:
await bot.send_document(message.chat.id, new_file)
@bot.message_handler(commands=['photos'])
async def photos_send(message: telebot.types.Message):
with open('test.png', 'rb') as new_file, open('test2.png', 'rb') as new_file2:
await bot.send_media_group(message.chat.id, [telebot.types.InputMediaPhoto(new_file), telebot.types.InputMediaPhoto(new_file2)])
bot.polling(skip_pending=True)

View File

@ -0,0 +1,13 @@
from telebot.async_telebot import AsyncTeleBot
bot = AsyncTeleBot('TOKEN')
@bot.message_handler(commands=['start', 'help'])
async def send_welcome(message):
await bot.reply_to(message, "Howdy, how are you doing?")
@bot.message_handler(func=lambda message: True)
async def echo_all(message):
await bot.reply_to(message, message.text)
bot.polling(skip_pending=True)# Skip pending skips old updates

View File

@ -0,0 +1,14 @@
from telebot.async_telebot import AsyncTeleBot
# Update listeners are functions that are called when any update is received.
bot = AsyncTeleBot(token='TOKEN')
async def update_listener(messages):
for message in messages:
if message.text == '/start':
await bot.send_message(message.chat.id, 'Hello!')
bot.set_update_listener(update_listener)
bot.polling()

View File

@ -0,0 +1,11 @@
import telebot
bot = telebot.TeleBot('TOKEN')
@bot.chat_join_request_handler()
def make_some(message: telebot.types.ChatJoinRequest):
bot.send_message(message.chat.id, 'I accepted a new user!')
bot.approve_chat_join_request(message.chat.id, message.from_user.id)
bot.infinity_polling(allowed_updates=telebot.util.update_types)

View File

@ -0,0 +1,33 @@
import telebot
from telebot import types,util
bot = telebot.TeleBot("token")
#chat_member_handler. When status changes, telegram gives update. check status from old_chat_member and new_chat_member.
@bot.chat_member_handler()
def chat_m(message: types.ChatMemberUpdated):
old = message.old_chat_member
new = message.new_chat_member
if new.status == "member":
bot.send_message(message.chat.id,"Hello {name}!".format(name=new.user.first_name)) # Welcome message
#if bot is added to group, this handler will work
@bot.my_chat_member_handler()
def my_chat_m(message: types.ChatMemberUpdated):
old = message.old_chat_member
new = message.new_chat_member
if new.status == "member":
bot.send_message(message.chat.id,"Somebody added me to group") # Welcome message, if bot was added to group
bot.leave_chat(message.chat.id)
#content_Type_service is:
#'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created',
#'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message',
#'proximity_alert_triggered', 'voice_chat_scheduled', 'voice_chat_started', 'voice_chat_ended',
#'voice_chat_participants_invited', 'message_auto_delete_timer_changed'
# this handler deletes service messages
@bot.message_handler(content_types=util.content_type_service)
def delall(message: types.Message):
bot.delete_message(message.chat.id,message.message_id)
bot.infinity_polling(allowed_updates=util.update_types)

View File

@ -0,0 +1,12 @@
import telebot
from telebot import custom_filters
bot = telebot.TeleBot('TOKEN')
# Handler
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True)
def answer_for_admin(message):
bot.send_message(message.chat.id,"hello my admin")
# Register filter
bot.add_custom_filter(custom_filters.IsAdminFilter(bot))
bot.infinity_polling()

View File

@ -0,0 +1,42 @@
import telebot
bot = telebot.TeleBot('TOKEN')
# AdvancedCustomFilter is for list, string filter values
class MainFilter(telebot.custom_filters.AdvancedCustomFilter):
key='text'
@staticmethod
def check(message, text):
return message.text in text
# SimpleCustomFilter is for boolean values, such as is_admin=True
class IsAdmin(telebot.custom_filters.SimpleCustomFilter):
key='is_admin'
@staticmethod
def check(message: telebot.types.Message):
return bot.get_chat_member(message.chat.id,message.from_user.id).status in ['administrator','creator']
@bot.message_handler(is_admin=True, commands=['admin']) # Check if user is admin
def admin_rep(message):
bot.send_message(message.chat.id, "Hi admin")
@bot.message_handler(is_admin=False, commands=['admin']) # If user is not admin
def not_admin(message):
bot.send_message(message.chat.id, "You are not admin")
@bot.message_handler(text=['hi']) # Response to hi message
def welcome_hi(message):
bot.send_message(message.chat.id, 'You said hi')
@bot.message_handler(text=['bye']) # Response to bye message
def bye_user(message):
bot.send_message(message.chat.id, 'You said bye')
# Do not forget to register filters
bot.add_custom_filter(MainFilter())
bot.add_custom_filter(IsAdmin())
bot.infinity_polling(skip_pending=True) # Skip old updates

View File

@ -0,0 +1,19 @@
import telebot
from telebot import custom_filters
bot = telebot.TeleBot('token')
# Chat id can be private or supergroups.
@bot.message_handler(chat_id=[12345678], commands=['admin']) # chat_id checks id corresponds to your list or not.
def admin_rep(message):
bot.send_message(message.chat.id, "You are allowed to use this command.")
@bot.message_handler(commands=['admin'])
def not_admin(message):
bot.send_message(message.chat.id, "You are not allowed to use this command")
# Do not forget to register
bot.add_custom_filter(custom_filters.ChatFilter())
bot.infinity_polling()

View File

@ -0,0 +1,21 @@
import telebot
from telebot import custom_filters
bot = telebot.TeleBot('TOKEN')
# Check if message is a reply
@bot.message_handler(is_reply=True)
def start_filter(message):
bot.send_message(message.chat.id, "Looks like you replied to my message.")
# Check if message was forwarded
@bot.message_handler(is_forwarded=True)
def text_filter(message):
bot.send_message(message.chat.id, "I do not accept forwarded messages!")
# Do not forget to register filters
bot.add_custom_filter(custom_filters.IsReplyFilter())
bot.add_custom_filter(custom_filters.ForwardFilter())
bot.infinity_polling()

View File

@ -0,0 +1,21 @@
import telebot
from telebot import custom_filters
bot = telebot.TeleBot('TOKEN')
# Check if message starts with @admin tag
@bot.message_handler(text_startswith="@admin")
def start_filter(message):
bot.send_message(message.chat.id, "Looks like you are calling admin, wait...")
# Check if text is hi or hello
@bot.message_handler(text=['hi','hello'])
def text_filter(message):
bot.send_message(message.chat.id, "Hi, {name}!".format(name=message.from_user.first_name))
# Do not forget to register filters
bot.add_custom_filter(custom_filters.TextMatchFilter())
bot.add_custom_filter(custom_filters.TextStartsFilter())
bot.infinity_polling()

74
examples/custom_states.py Normal file
View File

@ -0,0 +1,74 @@
import telebot
from telebot import custom_filters
bot = telebot.TeleBot("")
class MyStates:
name = 1
surname = 2
age = 3
@bot.message_handler(commands=['start'])
def start_ex(message):
"""
Start command. Here we are starting state
"""
bot.set_state(message.from_user.id, MyStates.name)
bot.send_message(message.chat.id, 'Hi, write me a name')
@bot.message_handler(state="*", commands='cancel')
def any_state(message):
"""
Cancel state
"""
bot.send_message(message.chat.id, "Your state was cancelled.")
bot.delete_state(message.from_user.id)
@bot.message_handler(state=MyStates.name)
def name_get(message):
"""
State 1. Will process when user's state is 1.
"""
bot.send_message(message.chat.id, f'Now write me a surname')
bot.set_state(message.from_user.id, MyStates.surname)
with bot.retrieve_data(message.from_user.id) as data:
data['name'] = message.text
@bot.message_handler(state=MyStates.surname)
def ask_age(message):
"""
State 2. Will process when user's state is 2.
"""
bot.send_message(message.chat.id, "What is your age?")
bot.set_state(message.from_user.id, MyStates.age)
with bot.retrieve_data(message.from_user.id) as data:
data['surname'] = message.text
# result
@bot.message_handler(state=MyStates.age, is_digit=True)
def ready_for_answer(message):
with bot.retrieve_data(message.from_user.id) as data:
bot.send_message(message.chat.id, "Ready, take a look:\n<b>Name: {name}\nSurname: {surname}\nAge: {age}</b>".format(name=data['name'], surname=data['surname'], age=message.text), parse_mode="html")
bot.delete_state(message.from_user.id)
#incorrect number
@bot.message_handler(state=MyStates.age, is_digit=False)
def age_incorrect(message):
bot.send_message(message.chat.id, 'Looks like you are submitting a string in the field age. Please enter a number')
# register filters
bot.add_custom_filter(custom_filters.StateFilter(bot))
bot.add_custom_filter(custom_filters.IsDigitFilter())
# set saving states into file.
bot.enable_saving_states() # you can delete this if you do not need to save states
bot.infinity_polling(skip_pending=True)

View File

@ -1,3 +1,5 @@
#!/usr/bin/python
# This example shows how to implement deep linking (https://core.telegram.org/bots#deep-linking)
# with the pyTelegramBotAPI.
# Note: This is not a working, production-ready sample.
@ -31,34 +33,38 @@
# steps are not shown here. Only steps 5 to 7 are illustrated, some in pseudo-code, with this example.
import telebot
import time
bot = telebot.TeleBot('TOKEN')
def extract_unique_code(text):
# Extracts the unique_code from the sent /start command.
return text.split()[1] if len(text.split()) > 1 else None
def in_storage(unique_code):
# (pseudo-code) Should check if a unique code exists in storage
return True
def get_username_from_storage(unique_code):
# (pseudo-code) Does a query to the storage, retrieving the associated username
# Should be replaced by a real database-lookup.
return "ABC" if in_storage(unique_code) else None
def save_chat_id(chat_id, username):
# (pseudo-code) Save the chat_id->username to storage
# Should be replaced by a real database query.
pass
@bot.message_handler(commands=['start'])
def send_welcome(message):
unique_code = extract_unique_code(message.text)
if unique_code: # if the '/start' command contains a unique_code
if unique_code: # if the '/start' command contains a unique_code
username = get_username_from_storage(unique_code)
if username: # if the username exists in our database
if username: # if the username exists in our database
save_chat_id(message.chat.id, username)
reply = "Hello {0}, how are you?".format(username)
else:
@ -67,4 +73,5 @@ def send_welcome(message):
reply = "Please visit me via a provided URL from the website."
bot.reply_to(message, reply)
bot.polling()
bot.infinity_polling()

View File

@ -2,9 +2,10 @@
This is a detailed example using almost every command of the API
"""
import time
import telebot
from telebot import types
import time
TOKEN = '<token_string>'
@ -12,16 +13,16 @@ knownUsers = [] # todo: save these in a file,
userStep = {} # so they won't reset every time the bot restarts
commands = { # command description used in the "help" command
'start': 'Get used to the bot',
'help': 'Gives you information about the available commands',
'sendLongText': 'A test using the \'send_chat_action\' command',
'getImage': 'A test using multi-stage messages, custom keyboard, and media sending'
'start' : 'Get used to the bot',
'help' : 'Gives you information about the available commands',
'sendLongText': 'A test using the \'send_chat_action\' command',
'getImage' : 'A test using multi-stage messages, custom keyboard, and media sending'
}
imageSelect = types.ReplyKeyboardMarkup(one_time_keyboard=True) # create the image selection keyboard
imageSelect.add('cock', 'pussy')
imageSelect.add('Mickey', 'Minnie')
hideBoard = types.ReplyKeyboardHide() # if sent as reply_markup, will hide the keyboard
hideBoard = types.ReplyKeyboardRemove() # if sent as reply_markup, will hide the keyboard
# error handling if user isn't known yet
@ -33,7 +34,7 @@ def get_user_step(uid):
else:
knownUsers.append(uid)
userStep[uid] = 0
print "New user detected, who hasn't used \"/start\" yet"
print("New user detected, who hasn't used \"/start\" yet")
return 0
@ -45,7 +46,7 @@ def listener(messages):
for m in messages:
if m.content_type == 'text':
# print the sent message to the console
print str(m.chat.first_name) + " [" + str(m.chat.id) + "]: " + m.text
print(str(m.chat.first_name) + " [" + str(m.chat.id) + "]: " + m.text)
bot = telebot.TeleBot(TOKEN)
@ -104,15 +105,15 @@ def msg_image_select(m):
# for some reason the 'upload_photo' status isn't quite working (doesn't show at all)
bot.send_chat_action(cid, 'typing')
if text == "cock": # send the appropriate image based on the reply to the "/getImage" command
if text == 'Mickey': # send the appropriate image based on the reply to the "/getImage" command
bot.send_photo(cid, open('rooster.jpg', 'rb'),
reply_markup=hideBoard) # send file and hide keyboard, after image is sent
userStep[cid] = 0 # reset the users step back to 0
elif text == "pussy":
elif text == 'Minnie':
bot.send_photo(cid, open('kitten.jpg', 'rb'), reply_markup=hideBoard)
userStep[cid] = 0
else:
bot.send_message(cid, "Don't type bullsh*t, if I give you a predefined keyboard!")
bot.send_message(cid, "Please, use the predefined keyboard!")
bot.send_message(cid, "Please try again")
@ -128,4 +129,5 @@ def command_default(m):
# this is the standard reply to a normal message
bot.send_message(m.chat.id, "I don't understand \"" + m.text + "\"\nMaybe try the help page at /help")
bot.polling()
bot.infinity_polling()

View File

@ -5,7 +5,7 @@ CHAT_ID = 'YOUR CHAT ID'
bot = telebot.TeleBot(TOKEN)
ret_msg = bot.send_voice(CHAT_ID, open('tests/test_data/record.ogg'))
ret_msg = bot.send_voice(CHAT_ID, open('tests/test_data/record.ogg', 'rb'))
file_info = bot.get_file(ret_msg.voice.file_id)

View File

@ -1,3 +1,5 @@
#!/usr/bin/python
# This is a simple echo bot using the decorator mechanism.
# It echoes any incoming text messages.
@ -7,6 +9,7 @@ API_TOKEN = '<api_token>'
bot = telebot.TeleBot(API_TOKEN)
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
@ -21,4 +24,5 @@ I am here to echo your kind words back to you. Just say anything nice and I'll s
def echo_message(message):
bot.reply_to(message, message.text)
bot.polling()
bot.infinity_polling()

View File

@ -1,11 +1,12 @@
# This example show how to write an inline mode telegramt bot use pyTelegramBotAPI.
import telebot
import time
import sys
# This example show how to write an inline mode telegram bot use pyTelegramBotAPI.
import logging
import sys
import time
import telebot
from telebot import types
API_TOKEN = '<api_token>'
API_TOKEN = '<TOKEN>'
bot = telebot.TeleBot(API_TOKEN)
telebot.logger.setLevel(logging.DEBUG)
@ -14,23 +15,24 @@ telebot.logger.setLevel(logging.DEBUG)
@bot.inline_handler(lambda query: query.query == 'text')
def query_text(inline_query):
try:
r = types.InlineQueryResultArticle('1', 'Result', inline_query.query)
r2 = types.InlineQueryResultArticle('2', 'Result2', inline_query.query)
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 == 'photo')
@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')
'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])
bot.answer_inline_query(inline_query.id, [r, r2], cache_time=1)
except Exception as e:
print(e)
@ -49,17 +51,17 @@ def query_video(inline_query):
print(e)
@bot.inline_handler(lambda query: len(query.query) is 0)
@bot.inline_handler(lambda query: len(query.query) == 0)
def default_query(inline_query):
try:
r = types.InlineQueryResultArticle('1', 'default', 'default')
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)
bot.infinity_polling()
while 1:
time.sleep(3)
@ -68,5 +70,5 @@ if __name__ == '__main__':
try:
main_loop()
except KeyboardInterrupt:
print >> sys.stderr, '\nExiting by user request.\n'
print('\nExiting by user request.\n')
sys.exit(0)

View File

@ -0,0 +1,27 @@
# This example show how to use inline keyboards and process button presses
import telebot
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
TELEGRAM_TOKEN = '<TOKEN>'
bot = telebot.TeleBot(TELEGRAM_TOKEN)
def gen_markup():
markup = InlineKeyboardMarkup()
markup.row_width = 2
markup.add(InlineKeyboardButton("Yes", callback_data="cb_yes"),
InlineKeyboardButton("No", callback_data="cb_no"))
return markup
@bot.callback_query_handler(func=lambda call: True)
def callback_query(call):
if call.data == "cb_yes":
bot.answer_callback_query(call.id, "Answer is Yes")
elif call.data == "cb_no":
bot.answer_callback_query(call.id, "Answer is No")
@bot.message_handler(func=lambda message: True)
def message_handler(message):
bot.send_message(message.chat.id, "Yes/no?", reply_markup=gen_markup())
bot.infinity_polling()

View File

@ -0,0 +1,53 @@
#!/usr/bin/python
# This example shows how to implement i18n (internationalization) l10n (localization) to create
# multi-language bots with middleware handler.
#
# Note: For the sake of simplicity of this example no extra library is used. However, it is recommended to use
# better i18n systems (gettext and etc) for handling multilingual translations.
# This is not a working, production-ready sample and it is highly recommended not to use it in production.
#
# In this example let's imagine we want to introduce localization or internationalization into our project and
# we need some global function to activate the language once and to use that language in all other message
# handler functions for not repeatedly activating it.
# The middleware (i18n and l10n) is explained:
import telebot
from telebot import apihelper
apihelper.ENABLE_MIDDLEWARE = True
TRANSLATIONS = {
'hello': {
'en': 'hello',
'ru': 'привет',
'uz': 'salom'
}
}
_lang = 'en'
def activate(lang):
global _lang
_lang = lang
def _(string):
return TRANSLATIONS[string][_lang]
bot = telebot.TeleBot('TOKEN')
@bot.middleware_handler(update_types=['message'])
def activate_language(bot_instance, message):
activate(message.from_user.language_code)
@bot.message_handler(commands=['start'])
def start(message):
bot.send_message(message.chat.id, _('hello'))
bot.infinity_polling()

View File

@ -0,0 +1,61 @@
#!/usr/bin/python
# This example shows how to implement session creation and retrieval based on user id with middleware handler.
#
# Note: For the sake of simplicity of this example no extra library is used. However, it is recommended to use
# in-memory or on-disk storage implementations (redis, mysql, postgres and etc) for storing and retrieving structures.
# This is not a working, production-ready sample and it is highly recommended not to use it in production.
#
# In this example let's imagine we want to create a session for each user who communicates with the bot to store
# different kind of temporary data while session is active. As an example we want to track the state of the user
# with the help of this session. So, we need a way to store this session data somewhere globally to enable other
# message handler functions to be able to use it.
# The middleware session is explained:
import telebot
from telebot import apihelper
apihelper.ENABLE_MIDDLEWARE = True
INFO_STATE = 'ON_INFO_MENU'
MAIN_STATE = 'ON_MAIN_MENU'
SESSIONS = {
-10000: {
'state': INFO_STATE
},
-11111: {
'state': MAIN_STATE
}
}
def get_or_create_session(user_id):
try:
return SESSIONS[user_id]
except KeyError:
SESSIONS[user_id] = {'state': MAIN_STATE}
return SESSIONS[user_id]
bot = telebot.TeleBot('TOKEN')
@bot.middleware_handler(update_types=['message'])
def set_session(bot_instance, message):
bot_instance.session = get_or_create_session(message.from_user.id)
@bot.message_handler(commands=['start'])
def start(message):
bot.session['state'] = MAIN_STATE
bot.send_message(message.chat.id, bot.session['state'])
@bot.message_handler(commands=['info'])
def start(message):
bot.session['state'] = INFO_STATE
bot.send_message(message.chat.id, bot.session['state'])
bot.infinity_polling()

View File

@ -0,0 +1,81 @@
import telebot
from telebot.types import LabeledPrice, 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.infinity_polling(skip_pending = True)

View File

@ -0,0 +1,21 @@
import telebot
api_token = 'token'
bot = telebot.TeleBot(api_token)
def start_executor(message):
bot.send_message(message.chat.id, 'Hello!')
bot.register_message_handler(start_executor, commands=['start']) # Start command executor
# See also
# bot.register_callback_query_handler(*args, **kwargs)
# bot.register_channel_post_handler(*args, **kwargs)
# bot.register_chat_member_handler(*args, **kwargs)
# bot.register_inline_handler(*args, **kwargs)
# bot.register_my_chat_member_handler(*args, **kwargs)
# bot.register_edited_message_handler(*args, **kwargs)
# And other functions..
bot.infinity_polling()

View File

@ -0,0 +1,69 @@
# Using Azure Functions for serverless bots.
# (Thanks to twitter.com/masyan for the idea)
# By default the Azure Functions url is https://.../api/HttpTrigger for HttpTrigger type.
# In this example we will use clear webhook url without /api/ -> https://.../HttpTrigger.
# Also we set "authLevel": "anonymous".
# For HttpTrigger type set "route" and "authLevel" in functions.json
# {
# "bindings": [
# ...
# "authLevel": "anonymous"
# "route": "HttpTrigger"
# ]
# }
# To avoid using /api/ in url set "routePrefix":"" in host.json
# {
# ...
# "extensions": {
# "http": {
# "routePrefix": ""
# }
# }
# }
import logging
import azure.functions as func
import telebot
from telebot import apihelper, types
logger = telebot.logger
telebot.logger.setLevel(logging.DEBUG)
# Set bot token
TOKEN = ''
# Uncomment this for using proxy for request
# PROXY = ''
# apihelper.proxy = {'https': PROXY}
# Set WEBHOOK as your Azure Functions url (https://...azurewebsites.net/HttpTrigger)
WEBHOOK = ''
bot = telebot.TeleBot(TOKEN)
@bot.message_handler(commands=['start'])
def start(message):
bot.reply_to(message, 'Hello, ' + message.from_user.first_name)
@bot.message_handler(func=lambda message: True, content_types=['text'])
def echo_message(message):
bot.reply_to(message, message.text)
# To avoid "error 429 too many request" set webhook only once. Or use time.sleep(1).
def main(req: func.HttpRequest) -> func.HttpResponse:
bot.set_webhook(url=WEBHOOK)
request_body_dict = req.get_json()
update = telebot.types.Update.de_json(request_body_dict)
bot.process_new_messages([update.message])
return func.HttpResponse(body='', status_code=200)
# Sometimes "requests" version is important.
# azure-functions==1.0.4
# PySocks==1.7.1
# pyTelegramBotAPI==3.6.6
# requests==2.10.0

View File

@ -0,0 +1,13 @@
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.infinity_polling(skip_pending=True)# Skip pending skips old updates

View File

@ -2,7 +2,6 @@
"""
This Example will show you how to use register_next_step handler.
"""
import time
import telebot
from telebot import types
@ -69,10 +68,19 @@ def process_sex_step(message):
if (sex == u'Male') or (sex == u'Female'):
user.sex = sex
else:
raise Exception()
raise Exception("Unknown sex")
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()
# Enable saving next step handlers to file "./.handlers-saves/step.save".
# Delay=2 means that after any change in next step handlers (e.g. calling register_next_step_handler())
# saving will hapen after delay 2 seconds.
bot.enable_save_next_step_handlers(delay=2)
# Load next_step_handlers from save file (default "./.handlers-saves/step.save")
# WARNING It will work only if enable_save_next_step_handlers was called!
bot.load_next_step_handlers()
bot.infinity_polling()

View File

@ -3,9 +3,10 @@
# and goes by the name 'TeleBot (@pyTeleBot)'. Join our group to talk to him!
# WARNING: Tested with Python 2.7
import telebot
import os
import telebot
text_messages = {
'welcome':
u'Please welcome {name}!\n\n'
@ -33,8 +34,10 @@ if "TELEBOT_BOT_TOKEN" not in os.environ or "GROUP_CHAT_ID" not in os.environ:
bot = telebot.AsyncTeleBot(os.environ["TELEBOT_BOT_TOKEN"])
GROUP_CHAT_ID = int(os.environ["GROUP_CHAT_ID"])
def is_api_group(chat_id):
return chat_id== GROUP_CHAT_ID
return chat_id == GROUP_CHAT_ID
@bot.message_handler(func=lambda m: True, content_types=['new_chat_participant'])
def on_user_joins(message):
@ -50,6 +53,7 @@ def on_user_joins(message):
bot.reply_to(message, text_messages['welcome'].format(name=name))
@bot.message_handler(commands=['info', 'help'])
def on_info(message):
if not is_api_group(message.chat.id):
@ -58,21 +62,23 @@ def on_info(message):
bot.reply_to(message, text_messages['info'])
@bot.message_handler(commands=["ping"])
def on_ping(message):
bot.reply_to(message, "Still alive and kicking!")
@bot.message_handler(commands=['start'])
def on_start(message):
if not is_api_group(message.chat.id):
bot.reply_to(message, text_messages['wrong_chat'])
return
def listener(messages):
for m in messages:
print str(m)
print(str(m))
bot.set_update_listener(listener)
bot.polling()
bot.infinity_polling()

View File

@ -1,6 +1,6 @@
# Webhook examples using pyTelegramBotAPI
There are 3 examples in this directory using different libraries:
There are 5 examples in this directory using different libraries:
* **Python (CPython):** *webhook_cpython_echo_bot.py*
* **Pros:**
@ -32,5 +32,23 @@ There are 3 examples in this directory using different libraries:
* 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 performance
* Utilizes new async/await syntax
* **Cons:**
* Requires Python 3.4.2+, don't work with Python 2
*Latest update of this document: 2015-10-06*
* **Twisted (20.3.0):** *webhook_twisted_echo_bot.py*
* **Pros:**
* Asynchronous event-driven networking engine
* Very high performance
* Built-in support for many internet protocols
* **Cons:**
* Twisted is low-level, which may be good or bad depending on use case
* Considerable learning curve - reading docs is a must.
*Latest update of this document: 2020-12-17*

View File

@ -0,0 +1,87 @@
#!/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

@ -4,10 +4,11 @@
# This is a simple echo bot using decorators and webhook with CherryPy
# It echoes any incoming text messages and does not use the polling method.
import cherrypy
import telebot
import logging
import cherrypy
import telebot
API_TOKEN = '<api_token>'
@ -29,7 +30,6 @@ WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT)
WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN)
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
@ -46,7 +46,7 @@ class WebhookServer(object):
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_messages([update.message])
bot.process_new_updates([update])
return ''
else:
raise cherrypy.HTTPError(403)
@ -70,14 +70,19 @@ def echo_message(message):
bot.remove_webhook()
# Set webhook
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
certificate=open(WEBHOOK_SSL_CERT, 'r'))
# Disable CherryPy requests log
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.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
})

View File

@ -4,11 +4,17 @@
# This is a simple echo bot using decorators and webhook with BaseHTTPServer
# It echoes any incoming text messages and does not use the polling method.
import BaseHTTPServer
import ssl
import telebot
import logging
try:
# Python 2
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
except ImportError:
# Python 3
from http.server import BaseHTTPRequestHandler, HTTPServer
import logging
import ssl
import telebot
API_TOKEN = '<api_token>'
@ -30,7 +36,6 @@ WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT)
WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN)
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
@ -38,7 +43,7 @@ bot = telebot.TeleBot(API_TOKEN)
# WebhookHandler, process webhook calls
class WebhookHandler(BaseHTTPServer.BaseHTTPRequestHandler):
class WebhookHandler(BaseHTTPRequestHandler):
server_version = "WebhookHandler/1.0"
def do_HEAD(self):
@ -81,15 +86,17 @@ def echo_message(message):
# Remove webhook, it fails sometimes the set if there is a previous webhook
bot.remove_webhook()
#bot.remove_webhook()
# Set webhook
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
certificate=open(WEBHOOK_SSL_CERT, 'r'))
# Beacuse telegram bot api server will check webhook server is alive.
# Here we need set webhook after server started manually.
#bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
# certificate=open(WEBHOOK_SSL_CERT, 'r'))
# Start server
httpd = BaseHTTPServer.HTTPServer((WEBHOOK_LISTEN, WEBHOOK_PORT),
WebhookHandler)
httpd = HTTPServer((WEBHOOK_LISTEN, WEBHOOK_PORT),
WebhookHandler)
httpd.socket = ssl.wrap_socket(httpd.socket,
certfile=WEBHOOK_SSL_CERT,

View File

@ -4,10 +4,12 @@
# This is a simple echo bot using decorators and webhook with flask
# It echoes any incoming text messages and does not use the polling method.
import flask
import telebot
import logging
import time
import flask
import telebot
API_TOKEN = '<api_token>'
@ -29,7 +31,6 @@ WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT)
WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN)
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
@ -48,9 +49,9 @@ def index():
@app.route(WEBHOOK_URL_PATH, methods=['POST'])
def webhook():
if flask.request.headers.get('content-type') == 'application/json':
json_string = flask.request.get_data()
json_string = flask.request.get_data().decode('utf-8')
update = telebot.types.Update.de_json(json_string)
bot.process_new_messages([update.message])
bot.process_new_updates([update])
return ''
else:
flask.abort(403)
@ -73,8 +74,10 @@ def echo_message(message):
# Remove webhook, it fails sometimes the set if there is a previous webhook
bot.remove_webhook()
time.sleep(0.1)
# Set webhook
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
certificate=open(WEBHOOK_SSL_CERT, 'r'))
# Start flask server

View File

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

View File

@ -0,0 +1,105 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This example shows webhook echo bot with Tornado web framework
# Documenation to Tornado: http://tornadoweb.org
import signal
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import telebot
API_TOKEN = '<api_token>'
WEBHOOK_CERT = "./cert.pem"
WEBHOOK_PKEY = "./pkey.pem"
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

@ -0,0 +1,79 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This is an example echo bot using webhook with Twisted network framework.
# Updates are received with Twisted web server and processed in reactor thread pool.
# Relevant docs:
# https://twistedmatrix.com/documents/current/core/howto/reactor-basics.html
# https://twistedmatrix.com/documents/current/web/howto/using-twistedweb.html
import logging
import telebot
import json
from twisted.internet import ssl, reactor
from twisted.web.resource import Resource, ErrorPage
from twisted.web.server import Site, Request
API_TOKEN = '<api_token>'
WEBHOOK_HOST = '<ip or hostname>'
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)
# 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'))
# Process webhook calls
class WebhookHandler(Resource):
isLeaf = True
def render_POST(self, request: Request):
request_body_dict = json.load(request.content)
update = telebot.types.Update.de_json(request_body_dict)
reactor.callInThread(lambda: bot.process_new_updates([update]))
return b''
root = ErrorPage(403, 'Forbidden', '')
root.putChild(API_TOKEN.encode(), WebhookHandler())
site = Site(root)
sslcontext = ssl.DefaultOpenSSLContextFactory(WEBHOOK_SSL_PRIV, WEBHOOK_SSL_CERT)
reactor.listenSSL(8443, site, sslcontext)
reactor.run()

View File

@ -1,5 +1,4 @@
py==1.4.29
pytest==2.7.2
requests==2.7.0
six==1.9.0
pytest==3.0.2
requests==2.20.0
wheel==0.24.0
aiohttp>=3.8.0,<3.9.0

View File

@ -1,26 +1,35 @@
#!/usr/bin/env python
from setuptools import setup
from io import open
import re
def readme():
with open('README.rst') as f:
return f.read()
def read(filename):
with open(filename, encoding='utf-8') as file:
return file.read()
with open('telebot/version.py', 'r', encoding='utf-8') as f: # Credits: LonamiWebs
version = re.search(r"^__version__\s*=\s*'(.*)'.*$",
f.read(), flags=re.MULTILINE).group(1)
setup(name='pyTelegramBotAPI',
version='1.4.1',
version=version,
description='Python Telegram bot api. ',
long_description=readme(),
long_description=read('README.md'),
long_description_content_type="text/markdown",
author='eternnoir',
author_email='eternnoir@gmail.com',
url='https://github.com/eternnoir/pyTelegramBotAPI',
packages=['telebot'],
license='GPL2',
keywords='telegram bot api tools',
install_requires=['pytest', 'requests', 'six'],
install_requires=['requests'],
extras_require={
'json': 'ujson',
'PIL': 'Pillow',
'redis': 'redis>=3.4.1'
},
classifiers=[
'Development Status :: 5 - Production/Stable',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Environment :: Console',
'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2881
telebot/async_telebot.py Normal file

File diff suppressed because it is too large Load Diff

178
telebot/asyncio_filters.py Normal file
View File

@ -0,0 +1,178 @@
from abc import ABC
class SimpleCustomFilter(ABC):
"""
Simple Custom Filter base class.
Create child class with check() method.
Accepts only message, returns bool value, that is compared with given in handler.
"""
async def check(self, message):
"""
Perform a check.
"""
pass
class AdvancedCustomFilter(ABC):
"""
Simple Custom Filter base class.
Create child class with check() method.
Accepts two parameters, returns bool: True - filter passed, False - filter failed.
message: Message class
text: Filter value given in handler
"""
async def check(self, message, text):
"""
Perform a check.
"""
pass
class TextMatchFilter(AdvancedCustomFilter):
"""
Filter to check Text message.
key: text
Example:
@bot.message_handler(text=['account'])
"""
key = 'text'
async def check(self, message, text):
if type(text) is list:return message.text in text
else: return text == message.text
class TextContainsFilter(AdvancedCustomFilter):
"""
Filter to check Text message.
key: text
Example:
# Will respond if any message.text contains word 'account'
@bot.message_handler(text_contains=['account'])
"""
key = 'text_contains'
async def check(self, message, text):
return text in message.text
class TextStartsFilter(AdvancedCustomFilter):
"""
Filter to check whether message starts with some text.
Example:
# Will work if message.text starts with 'Sir'.
@bot.message_handler(text_startswith='Sir')
"""
key = 'text_startswith'
async def check(self, message, text):
return message.text.startswith(text)
class ChatFilter(AdvancedCustomFilter):
"""
Check whether chat_id corresponds to given chat_id.
Example:
@bot.message_handler(chat_id=[99999])
"""
key = 'chat_id'
async def check(self, message, text):
return message.chat.id in text
class ForwardFilter(SimpleCustomFilter):
"""
Check whether message was forwarded from channel or group.
Example:
@bot.message_handler(is_forwarded=True)
"""
key = 'is_forwarded'
async def check(self, message):
return message.forward_from_chat is not None
class IsReplyFilter(SimpleCustomFilter):
"""
Check whether message is a reply.
Example:
@bot.message_handler(is_reply=True)
"""
key = 'is_reply'
async def check(self, message):
return message.reply_to_message is not None
class LanguageFilter(AdvancedCustomFilter):
"""
Check users language_code.
Example:
@bot.message_handler(language_code=['ru'])
"""
key = 'language_code'
async def check(self, message, text):
if type(text) is list:return message.from_user.language_code in text
else: return message.from_user.language_code == text
class IsAdminFilter(SimpleCustomFilter):
"""
Check whether the user is administrator / owner of the chat.
Example:
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True)
"""
key = 'is_chat_admin'
def __init__(self, bot):
self._bot = bot
async def check(self, message):
result = await self._bot.get_chat_member(message.chat.id, message.from_user.id)
return result.status in ['creator', 'administrator']
class StateFilter(AdvancedCustomFilter):
"""
Filter to check state.
Example:
@bot.message_handler(state=1)
"""
def __init__(self, bot):
self.bot = bot
key = 'state'
async def check(self, message, text):
result = await self.bot.current_states.current_state(message.from_user.id)
if result is False: return False
elif text == '*': return True
elif type(text) is list: return result in text
return result == text
class IsDigitFilter(SimpleCustomFilter):
"""
Filter to check whether the string is made up of only digits.
Example:
@bot.message_handler(is_digit=True)
"""
key = 'is_digit'
async def check(self, message):
return message.text.isdigit()

View File

@ -0,0 +1,219 @@
import os
import pickle
class StateMemory:
def __init__(self):
self._states = {}
async def add_state(self, chat_id, state):
"""
Add a state.
:param chat_id:
:param state: new state
"""
if chat_id in self._states:
self._states[chat_id]['state'] = state
else:
self._states[chat_id] = {'state': state,'data': {}}
async def current_state(self, chat_id):
"""Current state"""
if chat_id in self._states: return self._states[chat_id]['state']
else: return False
async def delete_state(self, chat_id):
"""Delete a state"""
self._states.pop(chat_id)
def _get_data(self, chat_id):
return self._states[chat_id]['data']
async def set(self, chat_id, new_state):
"""
Set a new state for a user.
:param chat_id:
:param new_state: new_state of a user
"""
await self.add_state(chat_id,new_state)
async def _add_data(self, chat_id, key, value):
result = self._states[chat_id]['data'][key] = value
return result
async def finish(self, chat_id):
"""
Finish(delete) state of a user.
:param chat_id:
"""
await self.delete_state(chat_id)
def retrieve_data(self, chat_id):
"""
Save input text.
Usage:
with bot.retrieve_data(message.chat.id) as data:
data['name'] = message.text
Also, at the end of your 'Form' you can get the name:
data['name']
"""
return StateContext(self, chat_id)
class StateFile:
"""
Class to save states in a file.
"""
def __init__(self, filename):
self.file_path = filename
async def add_state(self, chat_id, state):
"""
Add a state.
:param chat_id:
:param state: new state
"""
states_data = self._read_data()
if chat_id in states_data:
states_data[chat_id]['state'] = state
return await self._save_data(states_data)
else:
new_data = states_data[chat_id] = {'state': state,'data': {}}
return await self._save_data(states_data)
async def current_state(self, chat_id):
"""Current state."""
states_data = self._read_data()
if chat_id in states_data: return states_data[chat_id]['state']
else: return False
async def delete_state(self, chat_id):
"""Delete a state"""
states_data = self._read_data()
states_data.pop(chat_id)
await self._save_data(states_data)
def _read_data(self):
"""
Read the data from file.
"""
file = open(self.file_path, 'rb')
states_data = pickle.load(file)
file.close()
return states_data
def _create_dir(self):
"""
Create directory .save-handlers.
"""
dirs = self.file_path.rsplit('/', maxsplit=1)[0]
os.makedirs(dirs, exist_ok=True)
if not os.path.isfile(self.file_path):
with open(self.file_path,'wb') as file:
pickle.dump({}, file)
async def _save_data(self, new_data):
"""
Save data after editing.
:param new_data:
"""
with open(self.file_path, 'wb+') as state_file:
pickle.dump(new_data, state_file, protocol=pickle.HIGHEST_PROTOCOL)
return True
def _get_data(self, chat_id):
return self._read_data()[chat_id]['data']
async def set(self, chat_id, new_state):
"""
Set a new state for a user.
:param chat_id:
:param new_state: new_state of a user
"""
await self.add_state(chat_id,new_state)
async def _add_data(self, chat_id, key, value):
states_data = self._read_data()
result = states_data[chat_id]['data'][key] = value
await self._save_data(result)
return result
async def finish(self, chat_id):
"""
Finish(delete) state of a user.
:param chat_id:
"""
await self.delete_state(chat_id)
def retrieve_data(self, chat_id):
"""
Save input text.
Usage:
with bot.retrieve_data(message.chat.id) as data:
data['name'] = message.text
Also, at the end of your 'Form' you can get the name:
data['name']
"""
return StateFileContext(self, chat_id)
class StateContext:
"""
Class for data.
"""
def __init__(self , obj: StateMemory, chat_id) -> None:
self.obj = obj
self.chat_id = chat_id
self.data = obj._get_data(chat_id)
async def __aenter__(self):
return self.data
async def __aexit__(self, exc_type, exc_val, exc_tb):
return
class StateFileContext:
"""
Class for data.
"""
def __init__(self , obj: StateFile, chat_id) -> None:
self.obj = obj
self.chat_id = chat_id
self.data = None
async def __aenter__(self):
self.data = self.obj._get_data(self.chat_id)
return self.data
async def __aexit__(self, exc_type, exc_val, exc_tb):
old_data = self.obj._read_data()
for i in self.data:
old_data[self.chat_id]['data'][i] = self.data.get(i)
await self.obj._save_data(old_data)
return
class BaseMiddleware:
"""
Base class for middleware.
Your middlewares should be inherited from this class.
"""
def __init__(self):
pass
async def pre_process(self, message, data):
raise NotImplementedError
async def post_process(self, message, data, exception):
raise NotImplementedError

1635
telebot/asyncio_helper.py Normal file

File diff suppressed because it is too large Load Diff

115
telebot/callback_data.py Normal file
View File

@ -0,0 +1,115 @@
import typing
class CallbackDataFilter:
def __init__(self, factory, config: typing.Dict[str, str]):
self.config = config
self.factory = factory
def check(self, query):
"""
Checks if query.data appropriates to specified config
:param query: telebot.types.CallbackQuery
:return: bool
"""
try:
data = self.factory.parse(query.data)
except ValueError:
return False
for key, value in self.config.items():
if isinstance(value, (list, tuple, set, frozenset)):
if data.get(key) not in value:
return False
elif data.get(key) != value:
return False
return True
class CallbackData:
"""
Callback data factory
This class will help you to work with CallbackQuery
"""
def __init__(self, *parts, prefix: str, sep=':'):
if not isinstance(prefix, str):
raise TypeError(f'Prefix must be instance of str not {type(prefix).__name__}')
if not prefix:
raise ValueError("Prefix can't be empty")
if sep in prefix:
raise ValueError(f"Separator {sep!r} can't be used in prefix")
self.prefix = prefix
self.sep = sep
self._part_names = parts
def new(self, *args, **kwargs) -> str:
"""
Generate callback data
:param args: positional parameters of CallbackData instance parts
:param kwargs: named parameters
:return: str
"""
args = list(args)
data = [self.prefix]
for part in self._part_names:
value = kwargs.pop(part, None)
if value is None:
if args:
value = args.pop(0)
else:
raise ValueError(f'Value for {part!r} was not passed!')
if value is not None and not isinstance(value, str):
value = str(value)
if self.sep in value:
raise ValueError(f"Symbol {self.sep!r} is defined as the separator and can't be used in parts' values")
data.append(value)
if args or kwargs:
raise TypeError('Too many arguments were passed!')
callback_data = self.sep.join(data)
if len(callback_data.encode()) > 64:
raise ValueError('Resulted callback data is too long!')
return callback_data
def parse(self, callback_data: str) -> typing.Dict[str, str]:
"""
Parse data from the callback data
:param callback_data: string, use to telebot.types.CallbackQuery to parse it from string to a dict
:return: dict parsed from callback data
"""
prefix, *parts = callback_data.split(self.sep)
if prefix != self.prefix:
raise ValueError("Passed callback data can't be parsed with that prefix.")
elif len(parts) != len(self._part_names):
raise ValueError('Invalid parts count!')
result = {'@': prefix}
result.update(zip(self._part_names, parts))
return result
def filter(self, **config) -> CallbackDataFilter:
"""
Generate filter
:param config: specified named parameters will be checked with CallbackQury.data
:return: CallbackDataFilter class
"""
for key in config.keys():
if key not in self._part_names:
raise ValueError(f'Invalid field name {key!r}')
return CallbackDataFilter(self, config)

176
telebot/custom_filters.py Normal file
View File

@ -0,0 +1,176 @@
from abc import ABC
class SimpleCustomFilter(ABC):
"""
Simple Custom Filter base class.
Create child class with check() method.
Accepts only message, returns bool value, that is compared with given in handler.
"""
def check(self, message):
"""
Perform a check.
"""
pass
class AdvancedCustomFilter(ABC):
"""
Simple Custom Filter base class.
Create child class with check() method.
Accepts two parameters, returns bool: True - filter passed, False - filter failed.
message: Message class
text: Filter value given in handler
"""
def check(self, message, text):
"""
Perform a check.
"""
pass
class TextMatchFilter(AdvancedCustomFilter):
"""
Filter to check Text message.
key: text
Example:
@bot.message_handler(text=['account'])
"""
key = 'text'
def check(self, message, text):
if type(text) is list:return message.text in text
else: return text == message.text
class TextContainsFilter(AdvancedCustomFilter):
"""
Filter to check Text message.
key: text
Example:
# Will respond if any message.text contains word 'account'
@bot.message_handler(text_contains=['account'])
"""
key = 'text_contains'
def check(self, message, text):
return text in message.text
class TextStartsFilter(AdvancedCustomFilter):
"""
Filter to check whether message starts with some text.
Example:
# Will work if message.text starts with 'Sir'.
@bot.message_handler(text_startswith='Sir')
"""
key = 'text_startswith'
def check(self, message, text):
return message.text.startswith(text)
class ChatFilter(AdvancedCustomFilter):
"""
Check whether chat_id corresponds to given chat_id.
Example:
@bot.message_handler(chat_id=[99999])
"""
key = 'chat_id'
def check(self, message, text):
return message.chat.id in text
class ForwardFilter(SimpleCustomFilter):
"""
Check whether message was forwarded from channel or group.
Example:
@bot.message_handler(is_forwarded=True)
"""
key = 'is_forwarded'
def check(self, message):
return message.forward_from_chat is not None
class IsReplyFilter(SimpleCustomFilter):
"""
Check whether message is a reply.
Example:
@bot.message_handler(is_reply=True)
"""
key = 'is_reply'
def check(self, message):
return message.reply_to_message is not None
class LanguageFilter(AdvancedCustomFilter):
"""
Check users language_code.
Example:
@bot.message_handler(language_code=['ru'])
"""
key = 'language_code'
def check(self, message, text):
if type(text) is list:return message.from_user.language_code in text
else: return message.from_user.language_code == text
class IsAdminFilter(SimpleCustomFilter):
"""
Check whether the user is administrator / owner of the chat.
Example:
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True)
"""
key = 'is_chat_admin'
def __init__(self, bot):
self._bot = bot
def check(self, message):
return self._bot.get_chat_member(message.chat.id, message.from_user.id).status in ['creator', 'administrator']
class StateFilter(AdvancedCustomFilter):
"""
Filter to check state.
Example:
@bot.message_handler(state=1)
"""
def __init__(self, bot):
self.bot = bot
key = 'state'
def check(self, message, text):
if self.bot.current_states.current_state(message.from_user.id) is False: return False
elif text == '*': return True
elif type(text) is list: return self.bot.current_states.current_state(message.from_user.id) in text
return self.bot.current_states.current_state(message.from_user.id) == text
class IsDigitFilter(SimpleCustomFilter):
"""
Filter to check whether the string is made up of only digits.
Example:
@bot.message_handler(is_digit=True)
"""
key = 'is_digit'
def check(self, message):
return message.text.isdigit()

342
telebot/handler_backends.py Normal file
View File

@ -0,0 +1,342 @@
import os
import pickle
import threading
from telebot import apihelper
class HandlerBackend(object):
"""
Class for saving (next step|reply) handlers
"""
def __init__(self, handlers=None):
if handlers is None:
handlers = {}
self.handlers = handlers
def register_handler(self, handler_group_id, handler):
raise NotImplementedError()
def clear_handlers(self, handler_group_id):
raise NotImplementedError()
def get_handlers(self, handler_group_id):
raise NotImplementedError()
class MemoryHandlerBackend(HandlerBackend):
def register_handler(self, handler_group_id, handler):
if handler_group_id in self.handlers:
self.handlers[handler_group_id].append(handler)
else:
self.handlers[handler_group_id] = [handler]
def clear_handlers(self, handler_group_id):
self.handlers.pop(handler_group_id, None)
def get_handlers(self, handler_group_id):
return self.handlers.pop(handler_group_id, None)
def load_handlers(self, filename, del_file_after_loading):
raise NotImplementedError()
class FileHandlerBackend(HandlerBackend):
def __init__(self, handlers=None, filename='./.handler-saves/handlers.save', delay=120):
super(FileHandlerBackend, self).__init__(handlers)
self.filename = filename
self.delay = delay
self.timer = threading.Timer(delay, self.save_handlers)
def register_handler(self, handler_group_id, handler):
if handler_group_id in self.handlers:
self.handlers[handler_group_id].append(handler)
else:
self.handlers[handler_group_id] = [handler]
self.start_save_timer()
def clear_handlers(self, handler_group_id):
self.handlers.pop(handler_group_id, None)
self.start_save_timer()
def get_handlers(self, handler_group_id):
handlers = self.handlers.pop(handler_group_id, None)
self.start_save_timer()
return handlers
def start_save_timer(self):
if not self.timer.is_alive():
if self.delay <= 0:
self.save_handlers()
else:
self.timer = threading.Timer(self.delay, self.save_handlers)
self.timer.start()
def save_handlers(self):
self.dump_handlers(self.handlers, self.filename)
def load_handlers(self, filename=None, del_file_after_loading=True):
if not filename:
filename = self.filename
tmp = self.return_load_handlers(filename, del_file_after_loading=del_file_after_loading)
if tmp is not None:
self.handlers.update(tmp)
@staticmethod
def dump_handlers(handlers, filename, file_mode="wb"):
dirs = filename.rsplit('/', maxsplit=1)[0]
os.makedirs(dirs, exist_ok=True)
with open(filename + ".tmp", file_mode) as file:
if (apihelper.CUSTOM_SERIALIZER is None):
pickle.dump(handlers, file)
else:
apihelper.CUSTOM_SERIALIZER.dump(handlers, file)
if os.path.isfile(filename):
os.remove(filename)
os.rename(filename + ".tmp", filename)
@staticmethod
def return_load_handlers(filename, del_file_after_loading=True):
if os.path.isfile(filename) and os.path.getsize(filename) > 0:
with open(filename, "rb") as file:
if (apihelper.CUSTOM_SERIALIZER is None):
handlers = pickle.load(file)
else:
handlers = apihelper.CUSTOM_SERIALIZER.load(file)
if del_file_after_loading:
os.remove(filename)
return handlers
class RedisHandlerBackend(HandlerBackend):
def __init__(self, handlers=None, host='localhost', port=6379, db=0, prefix='telebot', password=None):
super(RedisHandlerBackend, self).__init__(handlers)
from redis import Redis
self.prefix = prefix
self.redis = Redis(host, port, db, password)
def _key(self, handle_group_id):
return ':'.join((self.prefix, str(handle_group_id)))
def register_handler(self, handler_group_id, handler):
handlers = []
value = self.redis.get(self._key(handler_group_id))
if value:
handlers = pickle.loads(value)
handlers.append(handler)
self.redis.set(self._key(handler_group_id), pickle.dumps(handlers))
def clear_handlers(self, handler_group_id):
self.redis.delete(self._key(handler_group_id))
def get_handlers(self, handler_group_id):
handlers = None
value = self.redis.get(self._key(handler_group_id))
if value:
handlers = pickle.loads(value)
self.clear_handlers(handler_group_id)
return handlers
class StateMemory:
def __init__(self):
self._states = {}
def add_state(self, chat_id, state):
"""
Add a state.
:param chat_id:
:param state: new state
"""
if chat_id in self._states:
self._states[chat_id]['state'] = state
else:
self._states[chat_id] = {'state': state,'data': {}}
def current_state(self, chat_id):
"""Current state"""
if chat_id in self._states: return self._states[chat_id]['state']
else: return False
def delete_state(self, chat_id):
"""Delete a state"""
self._states.pop(chat_id)
def _get_data(self, chat_id):
return self._states[chat_id]['data']
def set(self, chat_id, new_state):
"""
Set a new state for a user.
:param chat_id:
:param new_state: new_state of a user
"""
self.add_state(chat_id,new_state)
def _add_data(self, chat_id, key, value):
result = self._states[chat_id]['data'][key] = value
return result
def finish(self, chat_id):
"""
Finish(delete) state of a user.
:param chat_id:
"""
self.delete_state(chat_id)
def retrieve_data(self, chat_id):
"""
Save input text.
Usage:
with bot.retrieve_data(message.chat.id) as data:
data['name'] = message.text
Also, at the end of your 'Form' you can get the name:
data['name']
"""
return StateContext(self, chat_id)
class StateFile:
"""
Class to save states in a file.
"""
def __init__(self, filename):
self.file_path = filename
def add_state(self, chat_id, state):
"""
Add a state.
:param chat_id:
:param state: new state
"""
states_data = self._read_data()
if chat_id in states_data:
states_data[chat_id]['state'] = state
return self._save_data(states_data)
else:
new_data = states_data[chat_id] = {'state': state,'data': {}}
return self._save_data(states_data)
def current_state(self, chat_id):
"""Current state."""
states_data = self._read_data()
if chat_id in states_data: return states_data[chat_id]['state']
else: return False
def delete_state(self, chat_id):
"""Delete a state"""
states_data = self._read_data()
states_data.pop(chat_id)
self._save_data(states_data)
def _read_data(self):
"""
Read the data from file.
"""
file = open(self.file_path, 'rb')
states_data = pickle.load(file)
file.close()
return states_data
def _create_dir(self):
"""
Create directory .save-handlers.
"""
dirs = self.file_path.rsplit('/', maxsplit=1)[0]
os.makedirs(dirs, exist_ok=True)
if not os.path.isfile(self.file_path):
with open(self.file_path,'wb') as file:
pickle.dump({}, file)
def _save_data(self, new_data):
"""
Save data after editing.
:param new_data:
"""
with open(self.file_path, 'wb+') as state_file:
pickle.dump(new_data, state_file, protocol=pickle.HIGHEST_PROTOCOL)
return True
def _get_data(self, chat_id):
return self._read_data()[chat_id]['data']
def set(self, chat_id, new_state):
"""
Set a new state for a user.
:param chat_id:
:param new_state: new_state of a user
"""
self.add_state(chat_id,new_state)
def _add_data(self, chat_id, key, value):
states_data = self._read_data()
result = states_data[chat_id]['data'][key] = value
self._save_data(result)
return result
def finish(self, chat_id):
"""
Finish(delete) state of a user.
:param chat_id:
"""
self.delete_state(chat_id)
def retrieve_data(self, chat_id):
"""
Save input text.
Usage:
with bot.retrieve_data(message.chat.id) as data:
data['name'] = message.text
Also, at the end of your 'Form' you can get the name:
data['name']
"""
return StateFileContext(self, chat_id)
class StateContext:
"""
Class for data.
"""
def __init__(self , obj: StateMemory, chat_id) -> None:
self.obj = obj
self.chat_id = chat_id
self.data = obj._get_data(chat_id)
def __enter__(self):
return self.data
def __exit__(self, exc_type, exc_val, exc_tb):
return
class StateFileContext:
"""
Class for data.
"""
def __init__(self , obj: StateFile, chat_id) -> None:
self.obj = obj
self.chat_id = chat_id
self.data = self.obj._get_data(self.chat_id)
def __enter__(self):
return self.data
def __exit__(self, exc_type, exc_val, exc_tb):
old_data = self.obj._read_data()
for i in self.data:
old_data[self.chat_id]['data'][i] = self.data.get(i)
self.obj._save_data(old_data)
return

File diff suppressed because it is too large Load Diff

View File

@ -1,82 +1,115 @@
# -*- coding: utf-8 -*-
import random
import re
import string
import threading
import sys
import six
from six import string_types
import traceback
from typing import Any, Callable, List, Dict, Optional, Union
# Python3 queue support.
# noinspection PyPep8Naming
import queue as Queue
import logging
from telebot import types
try:
import Queue
import ujson as json
except ImportError:
import queue as Queue
import json
from telebot import logger
try:
# noinspection PyPackageRequirements
from PIL import Image
from io import BytesIO
pil_imported = True
except:
pil_imported = False
MAX_MESSAGE_LENGTH = 4096
logger = logging.getLogger('TeleBot')
thread_local = threading.local()
content_type_media = [
'text', 'audio', 'animation', 'document', 'photo', 'sticker', 'video', 'video_note', 'voice', 'contact', 'dice', 'poll',
'venue', 'location'
]
content_type_service = [
'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created',
'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message',
'proximity_alert_triggered', 'voice_chat_scheduled', 'voice_chat_started', 'voice_chat_ended',
'voice_chat_participants_invited', 'message_auto_delete_timer_changed'
]
update_types = [
"update_id", "message", "edited_message", "channel_post", "edited_channel_post", "inline_query",
"chosen_inline_result", "callback_query", "shipping_query", "pre_checkout_query", "poll", "poll_answer",
"my_chat_member", "chat_member", "chat_join_request"
]
class WorkerThread(threading.Thread):
count = 0
count = 0
def __init__(self, exception_callback=None, queue=None, name=None):
if not name:
name = "WorkerThread{0}".format(self.__class__.count + 1)
self.__class__.count += 1
if not queue:
queue = Queue.Queue()
def __init__(self, exception_callback=None, queue=None, name=None):
if not name:
name = "WorkerThread{0}".format(self.__class__.count + 1)
self.__class__.count += 1
if not queue:
queue = Queue.Queue()
threading.Thread.__init__(self, name=name)
self.queue = queue
self.daemon = True
threading.Thread.__init__(self, name=name)
self.queue = queue
self.daemon = True
self.received_task_event = threading.Event()
self.done_event = threading.Event()
self.exception_event = threading.Event()
self.continue_event = threading.Event()
self.received_task_event = threading.Event()
self.done_event = threading.Event()
self.exception_event = threading.Event()
self.continue_event = threading.Event()
self.exception_callback = exception_callback
self.exc_info = None
self._running = True
self.start()
self.exception_callback = exception_callback
self.exception_info = None
self._running = True
self.start()
def run(self):
while self._running:
try:
task, args, kwargs = self.queue.get(block=True, timeout=.5)
self.continue_event.clear()
self.received_task_event.clear()
self.done_event.clear()
self.exception_event.clear()
logger.debug("Received task")
self.received_task_event.set()
def run(self):
while self._running:
try:
task, args, kwargs = self.queue.get(block=True, timeout=.5)
self.continue_event.clear()
self.received_task_event.clear()
self.done_event.clear()
self.exception_event.clear()
logger.debug("Received task")
self.received_task_event.set()
task(*args, **kwargs)
logger.debug("Task complete")
self.done_event.set()
except Queue.Empty:
pass
except:
logger.debug("Exception occurred")
self.exc_info = sys.exc_info()
self.exception_event.set()
task(*args, **kwargs)
logger.debug("Task complete")
self.done_event.set()
except Queue.Empty:
pass
except Exception as e:
logger.debug(type(e).__name__ + " occurred, args=" + str(e.args) + "\n" + traceback.format_exc())
self.exception_info = e
self.exception_event.set()
if self.exception_callback:
self.exception_callback(self, self.exception_info)
self.continue_event.wait()
if self.exception_callback:
self.exception_callback(self, self.exc_info)
self.continue_event.wait()
def put(self, task, *args, **kwargs):
self.queue.put((task, args, kwargs))
def put(self, task, *args, **kwargs):
self.queue.put((task, args, kwargs))
def raise_exceptions(self):
if self.exception_event.is_set():
raise self.exception_info
def raise_exceptions(self):
if self.exception_event.is_set():
six.reraise(self.exc_info[0], self.exc_info[1], self.exc_info[2])
def clear_exceptions(self):
self.exception_event.clear()
self.continue_event.set()
def clear_exceptions(self):
self.exception_event.clear()
self.continue_event.set()
def stop(self):
self._running = False
def stop(self):
self._running = False
class ThreadPool:
@ -87,19 +120,19 @@ class ThreadPool:
self.num_threads = num_threads
self.exception_event = threading.Event()
self.exc_info = None
self.exception_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_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])
raise self.exception_info
def clear_exceptions(self):
self.exception_event.clear()
@ -124,20 +157,30 @@ class AsyncTask:
def _run(self):
try:
self.result = self.target(*self.args, **self.kwargs)
except:
self.result = sys.exc_info()
except Exception as e:
self.result = e
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])
raise self.result
else:
return self.result
def async():
class CustomRequestResponse():
def __init__(self, json_text, status_code = 200, reason = ""):
self.status_code = status_code
self.text = json_text
self.reason = reason
def json(self):
return json.loads(self.text)
def async_dec():
def decorator(fn):
def wrapper(*args, **kwargs):
return AsyncTask(fn, *args, **kwargs)
@ -148,18 +191,43 @@ def async():
def is_string(var):
return isinstance(var, string_types)
return isinstance(var, str)
def is_command(text):
def is_dict(var):
return isinstance(var, dict)
def is_bytes(var):
return isinstance(var, bytes)
def is_pil_image(var):
return pil_imported and isinstance(var, Image.Image)
def pil_image_to_file(image, extension='JPEG', quality='web_low'):
if pil_imported:
photoBuffer = BytesIO()
image.convert('RGB').save(photoBuffer, extension, quality=quality)
photoBuffer.seek(0)
return photoBuffer
else:
raise RuntimeError('PIL module is not imported')
def is_command(text: str) -> bool:
"""
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.
"""
if text is None: return False
return text.startswith('/')
def extract_command(text):
def extract_command(text: str) -> Union[str, None]:
"""
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.
@ -173,10 +241,28 @@ def extract_command(text):
:param text: String to extract the command from
:return: the command if `text` is a command (according to is_command), else None.
"""
if text is None: return None
return text.split()[0].split('@')[0][1:] if is_command(text) else None
def split_string(text, chars_per_string):
def extract_arguments(text: str) -> str:
"""
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(r"/\w*(@\w*)*\s*([\s\S]*)", re.IGNORECASE)
result = regexp.match(text)
return result.group(2) if is_command(text) else None
def split_string(text: str, chars_per_string: int) -> List[str]:
"""
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.
@ -187,6 +273,107 @@ def split_string(text, chars_per_string):
"""
return [text[i:i + chars_per_string] for i in range(0, len(text), chars_per_string)]
def smart_split(text: str, chars_per_string: int=MAX_MESSAGE_LENGTH) -> List[str]:
"""
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.
If `chars_per_string` > 4096: `chars_per_string` = 4096.
Splits by '\n', '. ' or ' ' in exactly this priority.
:param text: The text to split
:param chars_per_string: The number of maximum characters per part the text is split to.
:return: The splitted text as a list of strings.
"""
def _text_before_last(substr: str) -> str:
return substr.join(part.split(substr)[:-1]) + substr
if chars_per_string > MAX_MESSAGE_LENGTH: chars_per_string = MAX_MESSAGE_LENGTH
parts = []
while True:
if len(text) < chars_per_string:
parts.append(text)
return parts
part = text[:chars_per_string]
if "\n" in part: part = _text_before_last("\n")
elif ". " in part: part = _text_before_last(". ")
elif " " in part: part = _text_before_last(" ")
parts.append(part)
text = text[len(part):]
def escape(text: str) -> str:
"""
Replaces the following chars in `text` ('&' with '&amp;', '<' with '&lt;' and '>' with '&gt;').
:param text: the text to escape
:return: the escaped text
"""
chars = {"&": "&amp;", "<": "&lt;", ">": "&gt"}
for old, new in chars.items(): text = text.replace(old, new)
return text
def user_link(user: types.User, include_id: bool=False) -> str:
"""
Returns an HTML user link. This is useful for reports.
Attention: Don't forget to set parse_mode to 'HTML'!
Example:
bot.send_message(your_user_id, user_link(message.from_user) + ' started the bot!', parse_mode='HTML')
:param user: the user (not the user_id)
:param include_id: include the user_id
:return: HTML user link
"""
name = escape(user.first_name)
return (f"<a href='tg://user?id={user.id}'>{name}</a>"
+ (f" (<pre>{user.id}</pre>)" if include_id else ""))
def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int=2) -> types.InlineKeyboardMarkup:
"""
Returns a reply markup from a dict in this format: {'text': kwargs}
This is useful to avoid always typing 'btn1 = InlineKeyboardButton(...)' 'btn2 = InlineKeyboardButton(...)'
Example:
quick_markup({
'Twitter': {'url': 'https://twitter.com'},
'Facebook': {'url': 'https://facebook.com'},
'Back': {'callback_data': 'whatever'}
}, row_width=2):
returns an InlineKeyboardMarkup with two buttons in a row, one leading to Twitter, the other to facebook
and a back button below
kwargs can be:
{
'url': None,
'callback_data': None,
'switch_inline_query': None,
'switch_inline_query_current_chat': None,
'callback_game': None,
'pay': None,
'login_url': None
}
:param values: a dict containing all buttons to create in this format: {text: kwargs} {str:}
:param row_width: int row width
:return: InlineKeyboardMarkup
"""
markup = types.InlineKeyboardMarkup(row_width=row_width)
buttons = [
types.InlineKeyboardButton(text=text, **kwargs)
for text, kwargs in values.items()
]
markup.add(*buttons)
return markup
# CREDITS TO http://stackoverflow.com/questions/12317940#answer-12320352
def or_set(self):
self._set()
@ -199,16 +386,20 @@ def or_clear(self):
def orify(e, changed_callback):
e._set = e.set
e._clear = e.clear
if not hasattr(e, "_set"):
e._set = e.set
if not hasattr(e, "_clear"):
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]
bools = [ev.is_set() for ev in events]
if any(bools):
or_event.set()
else:
@ -224,3 +415,80 @@ def OrEvent(*events):
or_event.wait = busy_wait
changed()
return or_event
def per_thread(key, construct_value, reset=False):
if reset or not hasattr(thread_local, key):
value = construct_value()
setattr(thread_local, key, value)
return getattr(thread_local, key)
def chunks(lst, n):
"""Yield successive n-sized chunks from lst."""
# https://stackoverflow.com/a/312464/9935473
for i in range(0, len(lst), n):
yield lst[i:i + n]
def generate_random_token():
return ''.join(random.sample(string.ascii_letters, 16))
def deprecated(warn: bool=False, alternative: Optional[Callable]=None):
"""
Use this decorator to mark functions as deprecated.
When the function is used, an info (or warning if `warn` is True) is logged.
:param warn: If True a warning is logged else an info
:param alternative: The new function to use instead
"""
def decorator(function):
def wrapper(*args, **kwargs):
if not warn:
logger.info(f"`{function.__name__}` is deprecated."
+ (f" Use `{alternative.__name__}` instead" if alternative else ""))
else:
logger.warn(f"`{function.__name__}` is deprecated."
+ (f" Use `{alternative.__name__}` instead" if alternative else ""))
return function(*args, **kwargs)
return wrapper
return decorator
# Cloud helpers
def webhook_google_functions(bot, request):
"""A webhook endpoint for Google Cloud Functions FaaS."""
if request.is_json:
try:
request_json = request.get_json()
update = types.Update.de_json(request_json)
bot.process_new_updates([update])
return ''
except Exception as e:
print(e)
return 'Bot FAIL', 400
else:
return 'Bot ON'
def antiflood(function, *args, **kwargs):
"""
Use this function inside loops in order to avoid getting TooManyRequests error.
Example:
from telebot.util import antiflood
for chat_id in chat_id_list:
msg = antiflood(bot.send_message, chat_id, text)
You want get the
"""
from telebot.apihelper import ApiTelegramException
from time import sleep
try:
msg = function(*args, **kwargs)
except ApiTelegramException as ex:
if ex.error_code == 429:
sleep(ex.result_json['parameters']['retry_after'])
msg = function(*args, **kwargs)
finally:
return msg

3
telebot/version.py Normal file
View File

@ -0,0 +1,3 @@
# Versions should comply with PEP440.
# This line is parsed in setup.py:
__version__ = '4.2.1'

View File

@ -0,0 +1,277 @@
import sys
sys.path.append('../')
REDIS_TESTS = False
import os
import time
import pytest
import telebot
from telebot import types
from telebot.handler_backends import MemoryHandlerBackend, FileHandlerBackend
if REDIS_TESTS:
from telebot.handler_backends import RedisHandlerBackend
@pytest.fixture()
def telegram_bot():
return telebot.TeleBot('', threaded=False)
@pytest.fixture
def private_chat():
return types.Chat(id=11, type='private')
@pytest.fixture
def user():
return types.User(id=10, is_bot=False, first_name='Some User')
@pytest.fixture()
def message(user, private_chat):
params = {'text': '/start'}
return types.Message(
message_id=1, from_user=user, date=None, chat=private_chat, content_type='text', options=params, json_string=""
)
@pytest.fixture()
def reply_to_message(user, private_chat, message):
params = {'text': '/start'}
reply_message = types.Message(
message_id=2, from_user=user, date=None, chat=private_chat, content_type='text', options=params, json_string=""
)
reply_message.reply_to_message = message
return reply_message
@pytest.fixture()
def update_type(message):
edited_message = None
channel_post = None
edited_channel_post = None
inline_query = None
chosen_inline_result = None
callback_query = None
shipping_query = None
pre_checkout_query = None
poll = None
poll_answer = None
my_chat_member = None
chat_member = None
chat_join_request = None
return types.Update(1001234038283, message, edited_message, channel_post, edited_channel_post, inline_query,
chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll, poll_answer,
my_chat_member, chat_member, chat_join_request)
@pytest.fixture()
def reply_to_message_update_type(reply_to_message):
edited_message = None
channel_post = None
edited_channel_post = None
inline_query = None
chosen_inline_result = None
callback_query = None
shipping_query = None
pre_checkout_query = None
poll = None
poll_answer = None
my_chat_member = None
chat_member = None
chat_join_request = None
return types.Update(1001234038284, reply_to_message, edited_message, channel_post, edited_channel_post,
inline_query, chosen_inline_result, callback_query, shipping_query, pre_checkout_query,
poll, poll_answer, my_chat_member, chat_member, chat_join_request)
def next_handler(message):
message.text = 'entered next_handler'
def test_memory_handler_backend_default_backend(telegram_bot):
assert telegram_bot.reply_backend.__class__ == MemoryHandlerBackend
assert telegram_bot.next_step_backend.__class__ == MemoryHandlerBackend
def test_memory_handler_backend_register_next_step_handler(telegram_bot, private_chat, update_type):
@telegram_bot.message_handler(commands=['start'])
def start(message):
message.text = 'entered start'
telegram_bot.register_next_step_handler_by_chat_id(message.chat.id, next_handler)
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered start'
assert len(telegram_bot.next_step_backend.handlers[private_chat.id]) == 1
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered next_handler'
assert private_chat.id not in telegram_bot.next_step_backend.handlers
def test_memory_handler_backend_clear_next_step_handler(telegram_bot, private_chat, update_type):
@telegram_bot.message_handler(commands=['start'])
def start(message):
message.text = 'entered start'
telegram_bot.register_next_step_handler_by_chat_id(message.chat.id, next_handler)
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered start'
assert len(telegram_bot.next_step_backend.handlers[private_chat.id]) == 1
telegram_bot.clear_step_handler_by_chat_id(private_chat.id)
assert private_chat.id not in telegram_bot.next_step_backend.handlers
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered start'
def test_memory_handler_backend_register_reply_handler(telegram_bot, private_chat, update_type,
reply_to_message_update_type):
@telegram_bot.message_handler(commands=['start'])
def start(message):
message.text = 'entered start'
telegram_bot.register_for_reply_by_message_id(message.message_id, next_handler)
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered start'
assert len(telegram_bot.reply_backend.handlers[update_type.message.message_id]) == 1
telegram_bot.process_new_updates([reply_to_message_update_type])
assert reply_to_message_update_type.message.text == 'entered next_handler'
assert private_chat.id not in telegram_bot.reply_backend.handlers
def test_memory_handler_backend_clear_reply_handler(telegram_bot, private_chat, update_type,
reply_to_message_update_type):
@telegram_bot.message_handler(commands=['start'])
def start(message):
message.text = 'entered start'
telegram_bot.register_for_reply_by_message_id(message.message_id, next_handler)
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered start'
assert len(telegram_bot.reply_backend.handlers[update_type.message.message_id]) == 1
telegram_bot.clear_reply_handlers_by_message_id(update_type.message.message_id)
assert update_type.message.message_id not in telegram_bot.reply_backend.handlers
telegram_bot.process_new_updates([reply_to_message_update_type])
assert reply_to_message_update_type.message.text == 'entered start'
def test_file_handler_backend_register_next_step_handler(telegram_bot, private_chat, update_type):
telegram_bot.next_step_backend=FileHandlerBackend(filename='./.handler-saves/step1.save', delay=0.1)
@telegram_bot.message_handler(commands=['start'])
def start(message):
message.text = 'entered start'
telegram_bot.register_next_step_handler_by_chat_id(message.chat.id, next_handler)
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered start'
time.sleep(0.2)
assert os.path.exists(telegram_bot.next_step_backend.filename)
assert len(telegram_bot.next_step_backend.handlers[private_chat.id]) == 1
telegram_bot.next_step_backend.handlers = {}
telegram_bot.next_step_backend.load_handlers()
assert len(telegram_bot.next_step_backend.handlers[private_chat.id]) == 1
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered next_handler'
assert private_chat.id not in telegram_bot.next_step_backend.handlers
time.sleep(0.2)
if os.path.exists(telegram_bot.next_step_backend.filename):
os.remove(telegram_bot.next_step_backend.filename)
def test_file_handler_backend_clear_next_step_handler(telegram_bot, private_chat, update_type):
telegram_bot.next_step_backend=FileHandlerBackend(filename='./.handler-saves/step2.save', delay=0.1)
@telegram_bot.message_handler(commands=['start'])
def start(message):
message.text = 'entered start'
telegram_bot.register_next_step_handler_by_chat_id(message.chat.id, next_handler)
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered start'
assert len(telegram_bot.next_step_backend.handlers[private_chat.id]) == 1
time.sleep(0.2)
assert os.path.exists(telegram_bot.next_step_backend.filename)
telegram_bot.clear_step_handler_by_chat_id(private_chat.id)
time.sleep(0.2)
telegram_bot.next_step_backend.load_handlers()
assert private_chat.id not in telegram_bot.next_step_backend.handlers
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered start'
time.sleep(0.2)
if os.path.exists(telegram_bot.next_step_backend.filename):
os.remove(telegram_bot.next_step_backend.filename)
def test_redis_handler_backend_register_next_step_handler(telegram_bot, private_chat, update_type):
if not REDIS_TESTS:
pytest.skip('please install redis and configure redis server, then enable REDIS_TESTS')
telegram_bot.next_step_backend = RedisHandlerBackend(prefix='pyTelegramBotApi:step_backend1')
@telegram_bot.message_handler(commands=['start'])
def start(message):
message.text = 'entered start'
telegram_bot.register_next_step_handler_by_chat_id(message.chat.id, next_handler)
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered start'
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered next_handler'
def test_redis_handler_backend_clear_next_step_handler(telegram_bot, private_chat, update_type):
if not REDIS_TESTS:
pytest.skip('please install redis and configure redis server, then enable REDIS_TESTS')
telegram_bot.next_step_backend = RedisHandlerBackend(prefix='pyTelegramBotApi:step_backend2')
@telegram_bot.message_handler(commands=['start'])
def start(message):
message.text = 'entered start'
telegram_bot.register_next_step_handler_by_chat_id(message.chat.id, next_handler)
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered start'
telegram_bot.clear_step_handler_by_chat_id(private_chat.id)
telegram_bot.process_new_updates([update_type])
assert update_type.message.text == 'entered start'

View File

@ -6,6 +6,7 @@ sys.path.append('../')
import time
import pytest
import os
from datetime import datetime, timedelta
import telebot
from telebot import types
@ -16,6 +17,15 @@ 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']
def _new_test():
pass
@util.deprecated(alternative=_new_test)
def _test():
pass
@pytest.mark.skipif(should_skip, reason="No environment variables configured")
@ -47,7 +57,8 @@ class TestTeleBot:
bot = telebot.TeleBot('')
msg = self.create_text_message(r'https://web.telegram.org/')
@bot.message_handler(regexp='((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)')
# noinspection PyUnusedLocal
@bot.message_handler(regexp=r'((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)')
def command_url(message):
msg.text = 'got'
@ -59,6 +70,7 @@ class TestTeleBot:
bot = telebot.TeleBot('')
msg = self.create_text_message(r'lambda_text')
# noinspection PyUnusedLocal
@bot.message_handler(func=lambda message: r'lambda' in message.text)
def command_url(message):
msg.text = 'got'
@ -71,6 +83,7 @@ class TestTeleBot:
bot = telebot.TeleBot('')
msg = self.create_text_message(r'text')
# noinspection PyUnusedLocal
@bot.message_handler(func=lambda message: r'lambda' in message.text)
def command_url(message):
msg.text = 'got'
@ -83,7 +96,8 @@ class TestTeleBot:
bot = telebot.TeleBot('')
msg = self.create_text_message(r'web.telegram.org/')
@bot.message_handler(regexp='((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)')
# noinspection PyUnusedLocal
@bot.message_handler(regexp=r'((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)')
def command_url(message):
msg.text = 'got'
@ -101,6 +115,16 @@ class TestTeleBot:
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)
@ -110,18 +134,58 @@ class TestTeleBot:
ret_msg = tb.send_document(CHAT_ID, ret_msg.document.file_id)
assert ret_msg.message_id
def test_send_file_with_filename(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, file_data, visible_file_name="test.jpg")
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:
@ -140,10 +204,28 @@ class TestTeleBot:
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, 'eternnoir', 'pyTelegram')
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'
@ -154,6 +236,12 @@ class TestTeleBot:
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)
@ -162,12 +250,61 @@ class TestTeleBot:
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_dice(self):
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_dice(CHAT_ID, emoji='🎯')
assert ret_msg.message_id
assert ret_msg.content_type == 'dice'
def test_send_message_dis_noti(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
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)
@ -175,6 +312,20 @@ class TestTeleBot:
ret_msg = tb.forward_message(CHAT_ID, CHAT_ID, msg.message_id)
assert ret_msg.forward_from
def test_copy_message(self):
text = 'CI copy_message Test Message'
tb = telebot.TeleBot(TOKEN)
msg = tb.send_message(CHAT_ID, text)
ret_msg = tb.copy_message(CHAT_ID, CHAT_ID, msg.message_id)
assert ret_msg
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)
@ -203,6 +354,29 @@ class TestTeleBot:
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()
@ -210,10 +384,111 @@ class TestTeleBot:
assert me.id == msg.from_user.id
assert msg.chat.id == int(CHAT_ID)
def create_text_message(self, text):
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_edit_message_media(self):
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
file_data_2 = open('../examples/detailed_example/rooster.jpg', 'rb')
tb = telebot.TeleBot(TOKEN)
msg = tb.send_photo(CHAT_ID, file_data)
new_msg = tb.edit_message_media(chat_id=CHAT_ID, message_id=msg.message_id,
media=types.InputMediaPhoto(file_data_2, caption='Test editMessageMedia 0'))
assert type(new_msg) != bool
new_msg = tb.edit_message_media(chat_id=CHAT_ID, message_id=msg.message_id,
media=types.InputMediaPhoto(msg.photo[0].file_id, caption='Test editMessageMedia'))
assert type(new_msg) != bool
assert new_msg.caption == 'Test editMessageMedia'
def test_get_chat(self):
tb = telebot.TeleBot(TOKEN)
ch = tb.get_chat(GROUP_ID)
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_export_chat_invite_link(self):
tb = telebot.TeleBot(TOKEN)
il = tb.export_chat_invite_link(GROUP_ID)
assert isinstance(il, str)
def test_create_revoke_detailed_chat_invite_link(self):
tb = telebot.TeleBot(TOKEN)
cil = tb.create_chat_invite_link(GROUP_ID,
(datetime.now() + timedelta(minutes=1)).timestamp(), member_limit=5)
assert isinstance(cil.invite_link, str)
assert cil.creator.id == tb.get_me().id
assert isinstance(cil.expire_date, (float, int))
assert cil.member_limit == 5
assert not cil.is_revoked
rcil = tb.revoke_chat_invite_link(GROUP_ID, cil.invite_link)
assert rcil.is_revoked
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 test_antiflood(self):
text = "Flooding"
tb = telebot.TeleBot(TOKEN)
for _ in range(0,100):
util.antiflood(tb.send_message, CHAT_ID, text)
assert _
@staticmethod
def create_text_message(text):
params = {'text': text}
chat = types.User(11, 'test')
return types.Message(1, None, None, chat, 'text', params)
chat = types.User(11, False, 'test')
return types.Message(1, None, None, chat, 'text', params, "")
@staticmethod
def create_message_update(text):
params = {'text': text}
chat = types.User(11, False, 'test')
message = types.Message(1, None, None, chat, 'text', params, "")
edited_message = None
channel_post = None
edited_channel_post = None
inline_query = None
chosen_inline_result = None
callback_query = None
shipping_query = None
pre_checkout_query = None
poll = None
poll_answer = None
my_chat_member = None
chat_member = None
chat_join_request = None
return types.Update(-1001234038283, message, edited_message, channel_post, edited_channel_post, inline_query,
chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll, poll_answer,
my_chat_member, chat_member, chat_join_request)
def test_is_string_unicode(self):
s1 = u'string'
@ -226,3 +501,142 @@ class TestTeleBot:
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
def test_send_media_group(self):
tb = telebot.TeleBot(TOKEN)
img1 = 'https://i.imgur.com/CjXjcnU.png'
img2 = 'https://i.imgur.com/CjXjcnU.png'
medias = [types.InputMediaPhoto(img1, "View"), types.InputMediaPhoto(img2, "Dog")]
result = tb.send_media_group(CHAT_ID, medias)
assert len(result) == 2
assert result[0].media_group_id is not None
assert result[0].media_group_id == result[1].media_group_id
def test_send_media_group_local_files(self):
photo = open('../examples/detailed_example/kitten.jpg', 'rb')
video = open('./test_data/test_video.mp4', 'rb')
tb = telebot.TeleBot(TOKEN)
medias = [types.InputMediaPhoto(photo, "View"),
types.InputMediaVideo(video)]
result = tb.send_media_group(CHAT_ID, medias)
assert len(result) == 2
assert result[0].media_group_id is not None
assert result[1].media_group_id is not None
def test_send_photo_formating_caption(self):
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_photo(CHAT_ID, file_data, caption='_italic_', parse_mode='Markdown')
assert ret_msg.caption_entities[0].type == 'italic'
def test_send_video_formatting_caption(self):
file_data = open('./test_data/test_video.mp4', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_video(CHAT_ID, file_data, caption='_italic_', parse_mode='Markdown')
assert ret_msg.caption_entities[0].type == 'italic'
def test_send_audio_formatting_caption(self):
file_data = open('./test_data/record.mp3', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_audio(CHAT_ID, file_data, caption='<b>bold</b>', parse_mode='HTML')
assert ret_msg.caption_entities[0].type == 'bold'
def test_send_voice_formatting_caprion(self):
file_data = open('./test_data/record.ogg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_voice(CHAT_ID, file_data, caption='<b>bold</b>', parse_mode='HTML')
assert ret_msg.caption_entities[0].type == 'bold'
assert ret_msg.voice.mime_type == 'audio/ogg'
def test_send_media_group_formatting_caption(self):
tb = telebot.TeleBot(TOKEN)
img1 = 'https://i.imgur.com/CjXjcnU.png'
img2 = 'https://i.imgur.com/CjXjcnU.png'
medias = [types.InputMediaPhoto(img1, "*View*", parse_mode='Markdown'),
types.InputMediaPhoto(img2, "_Dog_", parse_mode='Markdown')]
result = tb.send_media_group(CHAT_ID, medias)
assert len(result) == 2
assert result[0].media_group_id is not None
assert result[0].caption_entities[0].type == 'bold'
assert result[1].caption_entities[0].type == 'italic'
def test_send_document_formating_caption(self):
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_document(CHAT_ID, file_data, caption='_italic_', parse_mode='Markdown')
assert ret_msg.caption_entities[0].type == 'italic'
def test_chat_commands(self):
tb = telebot.TeleBot(TOKEN)
command, description, lang = 'command_1', 'description of command 1', 'en'
scope = telebot.types.BotCommandScopeChat(CHAT_ID)
ret_msg = tb.set_my_commands([telebot.types.BotCommand(command, description)], scope, lang)
assert ret_msg is True
ret_msg = tb.get_my_commands(scope, lang)
assert ret_msg[0].command == command
assert ret_msg[0].description == description
ret_msg = tb.delete_my_commands(scope, lang)
assert ret_msg is True
ret_msg = tb.get_my_commands(scope, lang)
assert ret_msg == []
def test_typed_middleware_handler(self):
from telebot import apihelper
apihelper.ENABLE_MIDDLEWARE = True
tb = telebot.TeleBot('')
update = self.create_message_update('/help')
# noinspection PyUnusedLocal
@tb.middleware_handler(update_types=['message'])
def middleware(tb_instance, message):
message.text = 'got'
@tb.message_handler(func=lambda m: m.text == 'got')
def command_handler(message):
message.text = message.text + message.text
tb.process_new_updates([update])
time.sleep(1)
assert update.message.text == 'got' * 2
def test_default_middleware_handler(self):
from telebot import apihelper
apihelper.ENABLE_MIDDLEWARE = True
tb = telebot.TeleBot('')
update = self.create_message_update('/help')
# noinspection PyUnusedLocal
@tb.middleware_handler()
def middleware(tb_instance, mw_update):
mw_update.message.text = 'got'
@tb.message_handler(func=lambda m: m.text == 'got')
def command_handler(message):
message.text = message.text + message.text
tb.process_new_updates([update])
time.sleep(1)
assert update.message.text == 'got' * 2
def test_deprecated_dec(self):
_test()
def test_chat_permissions(self):
return # CHAT_ID is private chat, no permissions can be set
#tb = telebot.TeleBot(TOKEN)
#permissions = types.ChatPermissions(can_send_messages=True, can_send_polls=False)
#msg = tb.set_chat_permissions(CHAT_ID, permissions)

View File

@ -6,19 +6,51 @@ from telebot import types
def test_json_user():
jsonstring = r'{"id":101176298,"first_name":"RDSSBOT","username":"rdss_bot"}'
jsonstring = r'{"id":101176298,"first_name":"RDSSBOT","last_name":")))","username":"rdss_bot","is_bot":true}'
u = types.User.de_json(jsonstring)
assert u.id == 101176298
assert u.full_name == 'RDSSBOT )))'
def test_json_message():
jsonstring = r'{"message_id":1,"from":{"id":108929734,"first_name":"Frank","last_name":"Wang","username":"eternnoir"},"chat":{"id":1734,"first_name":"F","type":"private","last_name":"Wa","username":"oir"},"date":1435296025,"text":"HIHI"}'
jsonstring = r'{"message_id":1,"from":{"id":108929734,"first_name":"Frank","last_name":"Wang","username":"eternnoir","is_bot":true},"chat":{"id":1734,"first_name":"F","type":"private","last_name":"Wa","username":"oir"},"date":1435296025,"text":"HIHI"}'
msg = types.Message.de_json(jsonstring)
assert msg.text == 'HIHI'
def test_json_message_with_reply_markup():
jsonstring = r'{"message_id":48,"from":{"id":153587469,"is_bot":false,"first_name":"Neko","username":"Neko"},"chat":{"id":153587469,"first_name":"Neko","username":"Neko","type":"private"},"date":1598879570,"text":"test","reply_markup":{"inline_keyboard":[[{"text":"Google","url":"http://www.google.com"},{"text":"Yahoo","url":"http://www.yahoo.com"}]]}}'
msg = types.Message.de_json(jsonstring)
assert msg.content_type == 'text'
assert msg.reply_markup.keyboard[0][0].text == 'Google'
def test_json_InlineKeyboardMarkup():
jsonstring = r'{"inline_keyboard":[[{"text":"Google","url":"http://www.google.com"},{"text":"Yahoo","url":"http://www.yahoo.com"}]]}'
markup = types.InlineKeyboardMarkup.de_json(jsonstring)
assert markup.keyboard[0][0].text == 'Google'
assert markup.keyboard[0][1].url == 'http://www.yahoo.com'
def test_json_InlineKeyboardButton():
jsonstring = r'{"text":"Google","url":"http://www.google.com"}'
button = types.InlineKeyboardButton.de_json(jsonstring)
assert button.text == 'Google'
assert button.url == 'http://www.google.com'
def test_json_message_with_dice():
jsonstring = r'{"message_id":5560,"from":{"id":879343317,"is_bot":false,"first_name":"George","last_name":"Forse","username":"dr_fxrse","language_code":"ru"},"chat":{"id":879343317,"first_name":"George","last_name":"Forse","username":"dr_fxrse","type":"private"},"date":1586926330,"dice":{"value": 4, "emoji": "\ud83c\udfaf"}}'
msg = types.Message.de_json(jsonstring)
assert msg.content_type == 'dice'
assert isinstance(msg.dice, types.Dice)
assert msg.dice.value == 4
assert msg.dice.emoji == '🎯'
def test_json_message_group():
json_string = r'{"message_id":10,"from":{"id":12345,"first_name":"g","last_name":"G","username":"GG"},"chat":{"id":-866,"type":"private","title":"\u4ea4"},"date":1435303157,"text":"HIHI"}'
json_string = r'{"message_id":10,"from":{"id":12345,"first_name":"g","last_name":"G","username":"GG","is_bot":true},"chat":{"id":-866,"type":"private","title":"\u4ea4"},"date":1435303157,"text":"HIHI"}'
msg = types.Message.de_json(json_string)
assert msg.text == 'HIHI'
assert len(msg.chat.title) != 0
@ -32,14 +64,14 @@ def test_json_GroupChat():
def test_json_Document():
json_string = r'{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_size":446}'
json_string = r'{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AgADJQEAAqfhOEY","file_size":446}'
doc = types.Document.de_json(json_string)
assert doc.thumb is None
assert doc.file_name == 'Text File'
def test_json_Message_Audio():
json_string = r'{"message_id":131,"from":{"id":12775,"first_name":"dd","username":"dd"},"chat":{"id":10834,"first_name":"dd","type":"private","type":"private","last_name":"dd","username":"dd"},"date":1439978364,"audio":{"duration":1,"mime_type":"audio\/mpeg","title":"pyTelegram","performer":"eternnoir","file_id":"BQADBQADDH1JaB8-1KyWUss2-Ag","file_size":20096}}'
json_string = r'{"message_id":131,"from":{"id":12775,"first_name":"dd","username":"dd","is_bot":true },"chat":{"id":10834,"first_name":"dd","type":"private","type":"private","last_name":"dd","username":"dd"},"date":1439978364,"audio":{"duration":1,"mime_type":"audio\/mpeg","title":"pyTelegram","performer":"eternnoir","file_id":"BQADBQADDH1JaB8-1KyWUss2-Ag","file_unique_id": "AgADawEAAn8VSFY","file_size":20096}}'
msg = types.Message.de_json(json_string)
assert msg.audio.duration == 1
assert msg.content_type == 'audio'
@ -48,7 +80,7 @@ def test_json_Message_Audio():
def test_json_Message_Sticker():
json_string = r'{"message_id":98,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435479551,"sticker":{"width":550,"height":368,"thumb":{"file_id":"AAQFABPJLB0sAAQq17w-li3bzoIfAAIC","file_size":1822,"width":90,"height":60},"file_id":"BQADBQADNAIAAsYifgYdGJOa6bGAsQI","file_size":30320}}'
json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "thumb": {"file_id": "AAMCBAADHQJOFL7mAAJUMF8Dj62hpmDhpRAYvkc8CtIqipolAAJ8AAPA-8cF9yxjgjkLS97A0D4iXQARtQAHbQADHy4AAhoE", "file_unique_id": "AQADwNA-Il0AAx8uAAI", "file_size": 7776, "width": 60, "height": 60}, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}'
msg = types.Message.de_json(json_string)
assert msg.sticker.height == 368
assert msg.sticker.thumb.height == 60
@ -56,29 +88,29 @@ def test_json_Message_Sticker():
def test_json_Message_Sticker_without_thumb():
json_string = r'{"message_id":98,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435479551,"sticker":{"width":550,"height":368,"file_id":"BQADBQADNAIAAsYifgYdGJOa6bGAsQI","file_size":30320}}'
json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}'
msg = types.Message.de_json(json_string)
assert msg.sticker.height == 368
assert msg.sticker.thumb == None
assert msg.sticker.thumb is None
assert msg.content_type == 'sticker'
def test_json_Message_Document():
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_size":446}}'
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":446}}'
msg = types.Message.de_json(json_string)
assert msg.document.file_name == 'Text File'
assert msg.content_type == 'document'
def test_json_Message_Photo():
json_string = r'{"message_id":96,"from":{"id":109734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"dd","username":"dd"},"date":1435478191,"photo":[{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":615,"width":90,"height":67},{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":10174,"width":320,"height":240},{"file_id":"dd-A_LsTIABFNx-FUOaEa_3AABAQABAg","file_size":53013,"width":759,"height":570}]}'
json_string = r'{"message_id":96,"from":{"id":109734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"dd","username":"dd"},"date":1435478191,"photo":[{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":615,"width":90,"height":67},{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":10174,"width":320,"height":240},{"file_id":"dd-A_LsTIABFNx-FUOaEa_3AABAQABAg","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":53013,"width":759,"height":570}]}'
msg = types.Message.de_json(json_string)
assert len(msg.photo) == 3
assert msg.content_type == 'photo'
def test_json_Message_Video():
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_size":260699}}'
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_unique_id": "AQADTeisa3QAAz1nAAI","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_unique_id": "AgADbgEAAn8VSFY","file_size":260699}}'
msg = types.Message.de_json(json_string)
assert msg.video
assert msg.video.duration == 3
@ -87,39 +119,41 @@ def test_json_Message_Video():
def test_json_Message_Location():
json_string = r'{"message_id":102,"from":{"id":108734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":1089734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1535482469,"location":{"longitude":127.479471,"latitude":26.090577}}'
json_string = r'{"message_id":102,"from":{"id":108734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":1089734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1535482469,"location":{"longitude":127.479471,"latitude":26.090577}}'
msg = types.Message.de_json(json_string)
assert msg.location.latitude == 26.090577
assert msg.content_type == 'location'
def test_json_UserProfilePhotos():
json_string = r'{"total_count":1,"photos":[[{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAATZH_SpyZjzIwdVAAIC","file_size":6150,"width":160,"height":160},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAATOiTNi_YoJMghVAAIC","file_size":13363,"width":320,"height":320},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAAQW4DyFv0-lhglVAAIC","file_size":28347,"width":640,"height":640},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAAT50RvJCg0GQApVAAIC","file_size":33953,"width":800,"height":800}]]}'
json_string = r'{"total_count":1,"photos":[[{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAATZH_SpyZjzIwdVAAIC","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":6150,"width":160,"height":160},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAATOiTNi_YoJMghVAAIC","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":13363,"width":320,"height":320},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAAQW4DyFv0-lhglVAAIC","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":28347,"width":640,"height":640},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAAT50RvJCg0GQApVAAIC","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":33953,"width":800,"height":800}]]}'
upp = types.UserProfilePhotos.de_json(json_string)
assert upp.photos[0][0].width == 160
assert upp.photos[0][-1].height == 800
def test_json_contact():
json_string = r'{"phone_number":"00011111111","first_name":"dd","last_name":"ddl","user_id":8633}'
json_string = r'{"phone_number":"00011111111","first_name":"dd","last_name":"ddl","user_id":8633,"vcard":"SomeContactString"}'
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}'
json_string = r'{"duration": 0,"mime_type": "audio/ogg","file_id": "AwcccccccDH1JaB7w_gyFjYQxVAg","file_unique_id": "AgADbAEAAn8VSFY","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"}}'
json_string = r'{"update_id":938203,"message":{"message_id":241,"from":{"is_bot":true,"id":9734,"first_name":"Fk","last_name":"Wg","username":"nir"},"chat":{"id":1111,"first_name":"Fk","type":"private","last_name":"Wg","username":"oir"},"date":1441447009,"text":"HIHI"}}'
update = types.Update.de_json(json_string)
assert update.update_id == 938203
assert update.message.message_id == 241
assert update.message.from_user.id == 9734
def test_json_chat():
json_string = r'{"id": -111111,"title": "Test Title","type": "group"}'
chat = types.Chat.de_json(json_string)
@ -127,3 +161,87 @@ def test_json_chat():
assert chat.type == 'group'
assert chat.title == 'Test Title'
def test_InlineQueryResultCachedPhoto():
iq = types.InlineQueryResultCachedPhoto('aaa', 'Fileid')
json_str = iq.to_json()
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
def test_json_poll_1():
jsonstring = r'{"message_id": 395020,"from": {"id": 111,"is_bot": false,"first_name": "FN","last_name": "LN","username": "Badiboy","language_code": "ru"},"chat": {"id": 111,"first_name": "FN","last_name": "LN","username": "Badiboy","type": "private"},"date": 1587841239,"poll": {"id": "5272018969396510722","question": "Test poll 1","options": [{"text": "Answer 1","voter_count": 0},{"text": "Answer 2","voter_count": 0}],"total_voter_count": 0,"is_closed": false,"is_anonymous": true,"type": "regular","allows_multiple_answers": true}}'
msg = types.Message.de_json(jsonstring)
assert msg.poll is not None
assert isinstance(msg.poll, types.Poll)
assert msg.poll.id == '5272018969396510722'
assert msg.poll.question is not None
assert msg.poll.options is not None
assert len(msg.poll.options) == 2
assert msg.poll.allows_multiple_answers is True
def test_json_poll_answer():
jsonstring = r'{"poll_id": "5895675970559410186", "user": {"id": 329343347, "is_bot": false, "first_name": "Test", "username": "test_user", "last_name": "User", "language_code": "en"}, "option_ids": [1]}'
__import__('pprint').pprint(__import__('json').loads(jsonstring))
poll_answer = types.PollAnswer.de_json(jsonstring)
assert poll_answer.poll_id == '5895675970559410186'
assert isinstance(poll_answer.user, types.User)
assert poll_answer.option_ids == [1]
def test_KeyboardButtonPollType():
markup = types.ReplyKeyboardMarkup()
markup.add(types.KeyboardButton('send me a poll', request_poll=types.KeyboardButtonPollType(type='quiz')))
json_str = markup.to_json()
assert 'request_poll' in json_str
assert 'quiz' in json_str
def test_json_chat_invite_link():
json_string = r'{"invite_link":"https://t.me/joinchat/MeASP-Wi...","creator":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"ru"},"pending_join_request_count":1,"creates_join_request":true,"is_primary":false,"is_revoked":false}'
invite_link = types.ChatInviteLink.de_json(json_string)
assert invite_link.invite_link == 'https://t.me/joinchat/MeASP-Wi...'
assert isinstance(invite_link.creator, types.User)
assert not invite_link.is_primary
assert not invite_link.is_revoked
assert invite_link.expire_date is None
assert invite_link.member_limit is None
assert invite_link.name is None
assert invite_link.creator.id == 927266710
assert invite_link.pending_join_request_count == 1
assert invite_link.creates_join_request
def test_chat_member_updated():
json_string = r'{"chat": {"id": -1234567890123, "type": "supergroup", "title": "No Real Group", "username": "NoRealGroup"}, "from": {"id": 133869498, "is_bot": false, "first_name": "Vincent"}, "date": 1624119999, "old_chat_member": {"user": {"id": 77777777, "is_bot": false, "first_name": "Pepe"}, "status": "member"}, "new_chat_member": {"user": {"id": 77777777, "is_bot": false, "first_name": "Pepe"}, "status": "administrator"}}'
cm_updated = types.ChatMemberUpdated.de_json(json_string)
assert cm_updated.chat.id == -1234567890123
assert cm_updated.from_user.id == 133869498
assert cm_updated.date == 1624119999
assert cm_updated.old_chat_member.status == "member"
assert cm_updated.new_chat_member.status == "administrator"