Compare commits

...

361 Commits

Author SHA1 Message Date
_run e10517e088
Merge pull request #2017 from Artin-GH/patch-1
Fix backslash (\) issue in escape_markdown
2023-07-30 23:19:57 +05:00
Artin GH 1946393c36
Fix backslash (\) issue in escape_markdown 2023-07-14 16:39:50 +03:30
Badiboy 0f52ca688f
Merge pull request #2015 from Badiboy/master
Fix aioredis version check for regular redis
2023-07-14 13:00:03 +03:00
Badiboy b18bcd494a Fix aioredis version check for regular redis 2023-07-12 19:48:22 +03:00
Badiboy 8f41df0ee4
Merge pull request #2012 from Kourva/master
Update README.md
2023-07-10 19:01:09 +03:00
Kourva cb7f6a8c99
Update README.md 2023-07-10 03:05:34 +03:30
_run 3960115ec7
Merge pull request #2009 from coder2020official/fileupload
Fixes #1944: uploading file from memory
2023-07-09 00:06:02 +05:00
_run 916569cdc5
Fixes #1944: uploading file from memory 2023-07-08 23:42:47 +05:00
_run 75d3fa2eba
Merge pull request #2008 from coder2020official/middleware
Fix issue with post_process in async not receiving the error
2023-07-08 23:25:05 +05:00
_run 67e3774e8e
Fix issue with post_process in async not receiving the error 2023-07-08 23:23:23 +05:00
_run f799157314
Merge pull request #2007 from coder2020official/master
Updated all russian docstrings, currently without translation.
2023-07-08 23:15:05 +05:00
coder2020official af3a98057f Updated all russian docstrings, currently without translation. 2023-07-08 23:10:41 +05:00
_run 447fc1d461
Merge pull request #2006 from coder2020official/master
Fixed deprecation warning for readthedocs.org
2023-07-08 23:01:57 +05:00
_run fb98df3dfe
Fixed deprecation warning for readthedocs.org 2023-07-08 22:57:13 +05:00
Badiboy 0b34da3900
Merge pull request #1996 from artemetra/master
Fix typo in docs
2023-06-18 23:19:00 +03:00
Artem Lukin 5ea1abaadd
fix typo in docs 2023-06-18 01:57:08 +02:00
Badiboy 5a81353420
Merge pull request #1991 from eternnoir/dependabot/pip/requests-2.31.0
Bump requests from 2.20.0 to 2.31.0
2023-05-28 22:27:49 +03:00
dependabot[bot] eaf90cce7f
Bump requests from 2.20.0 to 2.31.0
Bumps [requests](https://github.com/psf/requests) from 2.20.0 to 2.31.0.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.20.0...v2.31.0)

---
updated-dependencies:
- dependency-name: requests
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-22 21:33:40 +00:00
Badiboy b219218c8d
Merge pull request #1988 from Badiboy/master
Bump version to 4.12.0
2023-05-18 18:09:13 +03:00
Badiboy 2dac17aa75 Bump version to 4.12.0 2023-05-18 18:07:09 +03:00
Badiboy 48377ac905
Merge pull request #1947 from alex75311/edit_antiflood_method
redesigned the antiflood method for guaranteed message delivery
2023-05-08 09:10:28 +03:00
Alexey Isaev 14294d1aa3 redesigned the antiflood method for guaranteed message delivery 2023-05-04 23:08:10 +03:00
_run ea3c159044
Merge pull request #1975 from engAmirEng/feature/async-func-filter
bring back the async func message_filter
2023-05-02 20:43:48 +04:00
AmirW 58d53e1a54 bring back the async func message_filter
-fixes #1974
- related commits: c84896391e f69a2ba044
2023-04-28 16:12:23 +03:30
Badiboy abec3dc60e
Merge pull request #1969 from coder2020official/botapi6.7
Bot API 6.7 - Not much to do, just minor improvements
2023-04-24 09:38:21 +03:00
coder2020official ecb5d9b4f6 Added tests for __html_text, fixed the bug, added custom_emoji for entities 2023-04-22 22:53:57 +04:00
coder2020official 26575dc5e7 Added support for launching Web Apps from inline query results by replacing the parameters switch_pm_text and switch_pm_parameter of the method answerInlineQuery with the parameter button of type InlineQueryResultsButton. 2023-04-22 20:51:08 +04:00
coder2020official be69feb252 * Added a test for message entity __html_text function. #1971 should be fixed and then todo can be done. 2023-04-22 20:38:05 +04:00
coder2020official 1d62adc262 Added the ability to get the current bot name in the given language as the class BotName using the method getMyName. 2023-04-22 18:30:46 +04:00
coder2020official 77e1928628 Added the ability to set different bot names for different user languages using the method setMyName. 2023-04-22 18:25:24 +04:00
coder2020official d6f4987197 Added the field via_chat_folder_invite_link to the class ChatMemberUpdated. 2023-04-21 22:30:32 +04:00
coder2020official 966b451869 Added the field switch_inline_query_chosen_chat of the type SwitchInlineQueryChosenChat to the class InlineKeyboardButton, which allows bots to switch to inline mode in a chosen chat of the given type. 2023-04-21 22:28:20 +04:00
coder2020official d1417e5616 Added the field web_app_name to the class WriteAccessAllowed. 2023-04-21 22:14:16 +04:00
_run a7cafd1f24
Update README.md 2023-04-21 21:27:08 +04:00
Badiboy 92907ced30
Merge pull request #1966 from Badiboy/master
Bump version to 4.11.0
2023-04-15 22:40:59 +03:00
Badiboy 1b2ed0e2f7 Bump version to 4.11.0 2023-04-15 22:39:14 +03:00
_run 370f0370c7
Merge pull request #1964 from Cub11k/add_state_list
Add state_list to StatesGroup
2023-04-15 01:53:00 +05:00
Cub11k e4bddd91cb Define state_list in __init_subclass__ 2023-04-14 22:11:08 +03:00
Cub11k d466da3542 Add state_list to StatesGroup 2023-04-14 22:00:42 +03:00
Badiboy e64c06b7bc
Merge pull request #1951 from mikelei8291/doc-fix
Fix documentation for `InlineKeyboardMarkup` and `quick_markup`
2023-04-03 19:10:10 +03:00
Badiboy 7d168ebbd8
Merge pull request #1961 from fcoagz/patch-2
Update README.md
2023-04-03 18:56:38 +03:00
Francisco Griman c5689f383b
edit 2023-04-03 11:49:21 -04:00
Francisco Griman 8796168efb
Update README.md 2023-04-03 11:27:15 -04:00
_run 100659fecd
Merge pull request #1958 from coder2020official/master
Fix storage not saving data sometimes
2023-04-03 01:01:11 +05:00
_run 7bf87a306a
Update redis_storage.py 2023-04-03 01:00:48 +05:00
_run 351d021e01
Update redis_storage.py 2023-04-03 01:00:29 +05:00
Badiboy 4ffe0f8833
Merge pull request #1952 from Badiboy/master
More changes from review of bot api 6.6
2023-03-27 23:17:24 +03:00
Badiboy 3f07dc4ce8
thumb
Co-authored-by: _run <khumogo1@gmail.com>
2023-03-26 20:04:29 +03:00
Badiboy 2e589ab6e1 Thumb type spec 2023-03-26 18:00:35 +03:00
Badiboy 8b63f6a6ef Merge branch 'master' of https://github.com/Badiboy/pyTelegramBotAPI 2023-03-26 17:41:25 +03:00
Badiboy dc98aca173 Merge remote-tracking branch 'upstream/master' 2023-03-26 17:40:55 +03:00
Badiboy 39360e0640
send_video thumbnail hint
Co-authored-by: _run <khumogo1@gmail.com>
2023-03-25 16:38:16 +03:00
Badiboy b1c172c421
send_document thumbnail hint
Co-authored-by: _run <khumogo1@gmail.com>
2023-03-25 16:38:05 +03:00
Badiboy 6b5c263ee8
send_animtion thumbnail hint
Co-authored-by: _run <khumogo1@gmail.com>
2023-03-25 16:37:46 +03:00
Badiboy 46100edd97
send_video_note thumbnail hint
Co-authored-by: _run <khumogo1@gmail.com>
2023-03-25 16:37:22 +03:00
Badiboy 018b89cdc0
send_document thumbnail
Co-authored-by: _run <khumogo1@gmail.com>
2023-03-25 16:37:03 +03:00
Badiboy f3486b3730
send_document thumbnail
Co-authored-by: _run <khumogo1@gmail.com>
2023-03-25 16:36:36 +03:00
Badiboy b0e64d828c
send_video thumbnail hint
Co-authored-by: _run <khumogo1@gmail.com>
2023-03-25 16:36:10 +03:00
Badiboy 14434b398e
send_animation thumbnail hint
Co-authored-by: _run <khumogo1@gmail.com>
2023-03-25 16:34:08 +03:00
_run 1d62bf2ac8
Merge pull request #1949 from codebyzen/master
I added CalendarIT Telegram bot (with link to bot), can post acquainted with what is happening today, tomorrow or what happened 20 years ago to channel.
2023-03-25 16:40:46 +04:00
Badiboy fe2e9a7a30 thumb_url etc. converted to properties 2023-03-25 15:22:30 +03:00
Badiboy c9ef0d71f0 Deprecation warnings equalisation 2023-03-25 15:17:29 +03:00
Badiboy b0740a920a Set "thumb" as property in types 2023-03-25 15:08:40 +03:00
Badiboy 6a9c25cf80 Fix set_sticker_set_thumb and set_sticker_set_thumbnail 2023-03-25 14:56:31 +03:00
Badiboy e56c60ac00 thumb deprecation typo and thumb->thumbnail param rename 2023-03-25 14:44:50 +03:00
Badiboy 7c7a063fb6 Fix some code hints 2023-03-25 14:38:02 +03:00
Mike Lei bd69492ed4
Fix documentation for `InlineKeyboardMarkup` and `quick_markup` 2023-03-23 18:52:40 +00:00
C̷̱̺͙͓̪͔̹͉͉̯̖̟̀͆́̽̔̈̚͠͝o̶̥̻̻̖̮͚͒̂̒͌̾̇͗͘͝d̸̢̡͈̮̦͈͙̖͔̦̭̩̰͎͉̣̰͆̈́͘͝e̸͖͆̎̏͒̀̈́͛́̍̀̀̿̚͝B̵̨̯̹̝͙͉̲̟̳̟͎̪̫̪̤̒͋̉̑̐̒̅̅̋͜y̵̞͚͕̭̤̱͖̟̫̜̓͐̏̕ͅZ̸͎̫̖͍̪̓̐͆e̶͈͇̽̔͂̉͊̈́ņ̶̣̣͎̤̯͖͉͍̳͇͈̘̳̗͚́̄̊̂̊̏̄͐͐̿̓́̽̃̄̚͝ 37cdb52ed2 Merge branch 'master' of https://github.com/eternnoir/pyTelegramBotAPI 2023-03-19 17:39:29 +03:00
C̷̱̺͙͓̪͔̹͉͉̯̖̟̀͆́̽̔̈̚͠͝o̶̥̻̻̖̮͚͒̂̒͌̾̇͗͘͝d̸̢̡͈̮̦͈͙̖͔̦̭̩̰͎͉̣̰͆̈́͘͝e̸͖͆̎̏͒̀̈́͛́̍̀̀̿̚͝B̵̨̯̹̝͙͉̲̟̳̟͎̪̫̪̤̒͋̉̑̐̒̅̅̋͜y̵̞͚͕̭̤̱͖̟̫̜̓͐̏̕ͅZ̸͎̫̖͍̪̓̐͆e̶͈͇̽̔͂̉͊̈́ņ̶̣̣͎̤̯͖͉͍̳͇͈̘̳̗͚́̄̊̂̊̏̄͐͐̿̓́̽̃̄̚͝ d8569394b0 Update README.md
I added CalendarIT Telegram bot, can post acquainted with what is happening today, tomorrow or what happened 20 years ago to channel.
2023-03-19 17:39:24 +03:00
_run da57174635
Merge pull request #1948 from coder2020official/botapi6.6
Changes from review of bot api 6.6
2023-03-19 18:25:37 +04:00
_run 776ce0a7eb
Merge pull request #1942 from arashnm80/master
add SpotSeekBot
2023-03-19 17:36:48 +04:00
coder2020official 886806135e Merge branch 'botapi6.6' of https://github.com/coder2020official/pyTelegramBotAPI into botapi6.6 2023-03-19 17:31:55 +04:00
coder2020official 1e450ebd15 Bot API 6.6 review changes 2023-03-19 17:31:53 +04:00
_run 41521f5618
Merge pull request #1937 from coder2020official/botapi6.6
I'm back: Bot API 6.6 Update
2023-03-19 13:27:52 +04:00
_run 603a7cf9f2
Update telebot/asyncio_helper.py 2023-03-15 05:48:41 +04:00
_run 535a14ca0c
Update telebot/apihelper.py 2023-03-15 05:48:16 +04:00
_run 67a52b2e98
Apply suggestions from code review 2023-03-15 05:46:03 +04:00
Arash Nemat Zadeh c47c26d2b0
Update README.md 2023-03-14 17:29:51 +03:30
coder2020official 9d2f7c02a4 Fixing tests attempt 1 2023-03-11 23:54:57 +04:00
coder2020official 991679bedc Renamed all necessary thumbs to thumbnails in types.py 2023-03-11 23:53:16 +04:00
coder2020official 3b4e6fed04 Renamed the method setStickerSetThumb to setStickerSetThumbnail and its parameter thumb to thumbnail. 2023-03-11 23:37:32 +04:00
coder2020official 5c6b867582 Renamed the field thumb in the classes Animation, Audio, Document, Sticker, Video, VideoNote, InputMediaAnimation, InputMediaAudio, InputMediaDocument, InputMediaVideo, StickerSet to thumbnail. Renamed the parameter thumb in the methods sendAnimation, sendAudio, sendDocument, sendVideo, sendVideoNote to thumbnail. 2023-03-11 23:34:17 +04:00
coder2020official 715aabaf49 Added the method setStickerMaskPosition for changing the mask position of a mask sticker. 2023-03-11 23:06:57 +04:00
coder2020official 9fa5b91e58 Added the method setStickerKeywords for changing the search keywords assigned to a sticker. 2023-03-11 22:58:41 +04:00
coder2020official de5a32e45c Fixed custom_emoji_ids and added set_sticker_emoji_list, and and fixed some typehints 2023-03-11 22:53:33 +04:00
coder2020official db087427fc Added the method deleteStickerSet for complete deletion of a given sticker set that was created by the bot. 2023-03-11 22:27:37 +04:00
coder2020official 385fc6a6da Added the method setStickerSetTitle for editing the title of sticker sets created by the bot. 2023-03-11 22:24:34 +04:00
coder2020official ac0b386625 Added the method setCustomEmojiStickerSetThumbnail for editing the thumbnail of custom emoji sticker sets created by the bot. 2023-03-11 22:19:49 +04:00
coder2020official ae44b0022d Added support for .WEBP, .TGS, and .WEBM files in uploadStickerFile by replacing the parameter png_sticker in the method uploadStickerFile with the parameters sticker and sticker_format. 2023-03-11 22:15:31 +04:00
coder2020official 73135d6012 Added support for .WEBP files in createNewStickerSet and addStickerToSet. 2023-03-11 22:03:37 +04:00
coder2020official 19dcce0d5b Added support for the creation of sticker sets with multiple initial stickers in createNewStickerSet by replacing the parameters png_sticker, tgs_sticker, webm_sticker, emojis and mask_position with the parameters stickers and sticker_format. 2023-03-11 21:59:22 +04:00
coder2020official f527fc91f6 Replaced the parameters png_sticker, tgs_sticker, webm_sticker, emojis and mask_position in the method addStickerToSet with the parameter sticker of the type InputSticker. 2023-03-11 18:18:07 +04:00
coder2020official c0185dad44 Added the field needs_repainting to the class Sticker. 2023-03-11 16:41:19 +04:00
coder2020official 8a858cac4e Added the parameter needs_repainting to the method createNewStickerSet to automatically change the color of emoji based on context (e.g., use text color in messages, accent color in statuses, etc.). 2023-03-11 16:39:04 +04:00
coder2020official f30457bd75 Added support for the creation of custom emoji sticker sets in createNewStickerSet. 2023-03-11 16:33:02 +04:00
coder2020official 54caf30f69 Added the parameter emoji to the method sendSticker to specify an emoji for just uploaded stickers. 2023-03-11 15:50:09 +04:00
coder2020official 09e4a2a437 Added the ability to get the current bot short description in the given language as the class BotShortDescription using the method getMyShortDescription. 2023-03-11 15:46:35 +04:00
coder2020official 9b81a29a6a Added the ability to set different bot short descriptions for different user languages using the method setMyShortDescription. 2023-03-11 15:40:54 +04:00
coder2020official 65dcd67140 Added the ability to get the current bot description in the given language as the class BotDescription using the method getMyDescription. 2023-03-11 15:35:00 +04:00
coder2020official c84b771e5a Added the ability to set different bot descriptions for different user languages using the method setMyDescription. 2023-03-10 21:36:44 +04:00
_run 2bd81a5f5c
I'm back: Bot API Update too :) 2023-03-10 15:21:07 +04:00
Badiboy 5d9a76b0dd
Merge pull request #1917 from S1RANN/master
Add a function to extract contents of entities from messages
2023-03-03 11:00:03 +03:00
Badiboy 6459f13f25
Merge pull request #1927 from Badiboy/master
New content types added + typo fix
2023-02-22 09:51:22 +03:00
Badiboy c9b6d3f868 New content types added + typo fix 2023-02-22 09:49:29 +03:00
Badiboy 80c1a4798d
Merge pull request #1921 from zeldpol/patch-1
Fix .webm upload
2023-02-18 23:46:03 +03:00
Dmitry 7a67d5f9f9
Fix .webm async upload 2023-02-18 22:36:29 +02:00
zeldpol d12ea91e12
Fix .webm upload
No need to pass file content as a header, it causes the http error "431 Request Header Fields Too Large".
2023-02-17 19:23:11 +02:00
orocane 4f2c89c4a8 Add a function to extract contents of entities from messages 2023-02-15 17:24:39 +08:00
_run fb7d60f09d
Merge pull request #1913 from coder2020official/botapi6.5
Fix #1912
2023-02-09 19:49:17 +04:00
coder2020official 8dc4e77287 Update asyncio_helper.py 2023-02-09 19:27:05 +04:00
Badiboy a999161384
Merge pull request #1911 from Badiboy/master
restrict_chat_member fix
2023-02-09 17:58:28 +03:00
Badiboy b4196f5891 restrict_chat_member fix 2023-02-09 17:56:10 +03:00
Badiboy e55fe962ca
Merge pull request #1906 from Badiboy/master
Bump version to 4.10.0
2023-02-05 13:14:08 +03:00
Badiboy 3d2c5c9590 Bump version to 4.10.0 2023-02-05 13:11:07 +03:00
_run 40567570e8
Merge pull request #1902 from coder2020official/botapi6.5
Bot API 6.5 update 🔥
2023-02-05 13:07:47 +04:00
coder2020official 4179e502c3 Fix description 2023-02-05 11:13:31 +04:00
coder2020official a9b878107c Fix can_send_media_messages param, added warnings 2023-02-04 22:24:26 +04:00
coder2020official 2094120ec7 Added user_chat_id to ChatJoinRequest; And, i corrected typehints 2023-02-04 20:07:01 +04:00
coder2020official d1348606e3 Added use_independent_chat_permissions to setchatpermissions 2023-02-04 20:04:07 +04:00
coder2020official d0d03d0c09 Added use_independent_chat_permissions for restrictchatmember 2023-02-04 19:59:49 +04:00
Badiboy fdd82a5e4b
Merge pull request #1894 from Muhammad-Aadil/master
Added poll_example.py in the examples
2023-02-04 18:46:39 +03:00
coder2020official 9e68f76f5d Replaced the fields can_send_media_messages in the classes ChatMemberRestricted and ChatPermissions with separate fields can_send_audios, can_send_documents, can_send_photos, can_send_videos, can_send_video_notes, and can_send_voice_notes for different media types. 2023-02-04 18:57:06 +04:00
coder2020official 4000c9fb48 Added chat_shared and chatshared 2023-02-04 16:58:48 +04:00
coder2020official ae42d0b1fe Added usershared and user_shared 2023-02-04 16:54:43 +04:00
coder2020official a3891ff363 Pep 0563 proposed change
https://peps.python.org/pep-0563/
2023-02-04 16:29:48 +04:00
coder2020official 4d7f5310fb Added the class KeyboardButtonRequestChat and the field request_chat to the class KeyboardButton. 2023-02-04 16:24:05 +04:00
_run 3e0d69f7f4
fixed checks x1 2023-02-04 16:16:34 +04:00
coder2020official 2e5fb10430 Added the class KeyboardButtonRequestUser and the field request_user to the class KeyboardButton. 2023-02-04 16:02:18 +04:00
_run c39c050abf
Update README.md 2023-02-04 15:32:55 +04:00
Muhammad Aadil ed6d6cc03f add poll answer handler to poll_example.py to show the example to send next poll or log user answers 2023-02-04 11:22:49 +05:00
Muhammad Aadil 10a80e1cfa add only quiz type poll example to the poll_example.py 2023-02-04 10:27:29 +05:00
Badiboy d99f48f975
Merge pull request #1893 from artyl/master
RuntimeError("cannot join current thread")
2023-01-31 20:52:59 +03:00
_run dae2790c61
Merge pull request #1898 from Badiboy/master
Async allowed_updates fix
2023-01-31 20:59:35 +04:00
Badiboy f5eac56afa Async allowed_updates fix 2023-01-31 11:19:11 +03:00
_run 268c3a9210
Merge pull request #1890 from iamnalinor/master
Fix "invite link must be non-empty" error
2023-01-28 19:35:02 +04:00
Muhammad Aadil ad7e4bbaf7 Added poll_example.py in the examples 2023-01-28 18:20:58 +05:00
Artem Lavrenov b9bedef73f Avoid raise RuntimeError(cannot join current thread) 2023-01-28 12:26:25 +03:00
Badiboy 9fb5f89f18
Merge pull request #1892 from bgelov/patch-1
Update README.md
2023-01-27 09:24:07 +03:00
Oleg Belov 409ff49603
Update README.md
Change _handeler() to _handler() in readme
2023-01-26 22:49:41 -03:00
Albert 5e0da40fcd Fix "invite link must be non-empty" error
`bot.edit_chat_invite_link` method contained a mistake: `invite_link` and `name` were supposed to be vice-versa in `apihelper.edit_chat_invite_link(...)` call. This caused to be invite_link empty or contain invalid value, resulting to get `Bad Request: invite link must be non-empty` error.
This also affected the async version.
2023-01-21 17:00:36 +04:00
Badiboy b743aa5813
Merge pull request #1884 from Cub11k/master
Remove redundant function from util
2023-01-16 16:58:58 +03:00
Cub11k 1797f076dc Remove redundant function 2023-01-16 15:45:59 +02:00
_run 68c1fe8cb5
Merge pull request #1883 from Cub11k/master
Fix type of attribute id of InlineQuery from int to str
2023-01-15 17:22:22 +04:00
Cub11k 1eda7cafd4 Fix type of attribute id of InlineQuery from int to str 2023-01-15 15:04:07 +02:00
Badiboy 291566908b
Merge pull request #1882 from CommanderCRM/patch-1
Added a bot with public source code to the list
2023-01-13 15:58:55 +03:00
Ilya Krivoshein bef29d9318
Added a bot with public source code to the list 2023-01-13 19:14:10 +07:00
Badiboy a5af586a46
Merge pull request #1881 from Cub11k/master
Create method get_media_file_id() in util.py
2023-01-10 20:48:50 +03:00
Cub11k 93dcbbeb02 Create method get_media_file_id()
Method is used to get file id of different types of media
2023-01-10 19:35:36 +02:00
Badiboy bd94d8d91c
Merge pull request #1873 from coder2020official/circular_import_fix
Little code style improvement in service_utils
2023-01-08 09:55:33 +03:00
_run 6b399ab8cd
Being specific with except block 2023-01-08 10:49:27 +04:00
_run 8744402efc
Removed built-in io module from try/except block 2023-01-08 10:48:45 +04:00
Badiboy d5bbaa900e
Merge pull request #1870 from Cub11k/master
Make create_dir() method of StatePickleStorage cross-platform instead of POSIX only.
2023-01-07 13:02:26 +03:00
Konstantin Ostashenko 02ae255701
Revert changes in util.py 2023-01-06 22:39:27 +02:00
Cub11k c27f60b94b Make create_dir() method cross-platform instead of POSIX only.
Fix for issue #1869
2023-01-06 22:36:08 +02:00
Badiboy a781929a2d
Merge pull request #1868 from Cub11k/master
Fix circular import
2023-01-06 22:51:52 +03:00
Cub11k e6f8acadf4 rename _util.py to service_utils.py 2023-01-06 21:41:30 +02:00
Cub11k c298d95d0f Move functions, required in types.py to _util.py
Add __all__ to util.py for sphinx to generate docs properly
2023-01-06 19:27:25 +02:00
Cub11k 8aee5372ee Update README.md - add link to ru docs 2023-01-05 16:25:16 +02:00
_run df105ab1d8
Merge pull request #1867 from Cub11k/master
Translated into russian files: index.po, calldata.po
2023-01-05 18:20:30 +04:00
Cub11k b93ec5d0e0 Translated calldata.po to russian 2023-01-05 16:13:00 +02:00
Cub11k f201df3275 Translated index.po to russian 2023-01-05 16:03:14 +02:00
_run 206e4e024b
Merge pull request #1865 from coder2020official/master
Fix docs issues
2023-01-04 18:08:35 +04:00
coder2020official bd1290592b Fix docs issues 2023-01-04 18:07:29 +04:00
_run 9b9eb775f7
Merge pull request #1863 from Cub11k/master
Finished translations into russian of files: sync_version.po, async_version.po
2023-01-04 17:39:34 +04:00
Konstantin Ostashenko 3cfa24f9c0
Fix msgid for forward_message:5 in async_version.po 2023-01-04 15:35:09 +02:00
Konstantin Ostashenko b540a6c4d4
Fix msgid for forward_message:5 in sync_version.po 2023-01-04 15:33:18 +02:00
Cub11k a0ba5ae9af Finished translations on sync and async versions.
Spelling fixes
2023-01-04 00:43:42 +02:00
Cub11k 651db29cb2 Fix typehints for stop_poll reply markup 2023-01-03 23:45:59 +02:00
Cub11k 490168f3f6 Some translations
Up to lines sync_version.po:4527 and async_version.po:4448
2023-01-03 19:43:36 +02:00
Cub11k bf38071e8f Some translations
Up to lines sync_version.po:3691 and async_version.po:3609
2023-01-03 17:32:31 +02:00
Konstantin Ostashenko e8aaa524fe
Merge branch 'sync_and_async_upd' into master 2023-01-02 17:41:48 +02:00
Konstantin Ostashenko e2e754fdff
Merge pull request #3 from eternnoir/master
Update fork
2023-01-02 17:35:04 +02:00
_run d64f305fd4
Merge pull request #1861 from coder2020official/docs
Updated documentation locales
2023-01-02 19:29:40 +04:00
coder2020official 611bf4235c Updated documentation locales 2023-01-02 19:27:57 +04:00
Konstantin Ostashenko fe0dc6930c
Merge pull request #2 from Cub11k/master
Update branch from master
2023-01-02 17:14:33 +02:00
Konstantin Ostashenko 6d4d3f8005
Merge pull request #1 from eternnoir/master
Update fork
2023-01-02 17:12:49 +02:00
Cub11k 0f7464e8c4 Some translations
Up to lines sync_version.po:3008 and async_version.po:3122
2023-01-02 17:09:48 +02:00
Badiboy 6f86382e33
Merge pull request #1860 from Badiboy/master
Bump version to 4.9/0
2023-01-02 18:00:39 +03:00
Badiboy 43cc203654 Bump version to 4.9/0 2023-01-02 18:00:20 +03:00
Badiboy 3b62ad4765
Merge pull request #1855 from coder2020official/botapi6.4
Bot API 6.4
2023-01-02 17:55:32 +03:00
_run 3be5015f9e
Update telebot/types.py 2023-01-02 17:55:30 +04:00
_run 267a33c329
Update telebot/types.py 2023-01-02 17:55:14 +04:00
_run 667e82d073
Update telebot/types.py 2023-01-02 17:54:35 +04:00
Cub11k dd50273c95 Some translations
Up to lines sync_version.po:2709 and async_version.po:2853
2022-12-31 14:16:13 +02:00
Cub11k 8e9d566d5c Minor fixes and some translations
Up to lines sync_version.po:2382 and async_version.po:2528
2022-12-31 00:56:38 +02:00
_run 79bc869143
Merge pull request #1856 from Cub11k/master
Copied translations from sync_version.po to async_version.po
2022-12-30 23:56:32 +04:00
Konstantin Ostashenko 68edb4990c
Fix async_version.po 2022-12-30 21:42:50 +02:00
Cub11k 19544ecc58 Copied translations from sync_version.po to async_version.po
Minor fixes in sync_version.po, found while copying
2022-12-30 21:24:13 +02:00
coder2020official eed56be596 Added fields has_hidden_members and has_aggressive_anti_spam_enabled to class Chat 2022-12-30 20:38:26 +04:00
coder2020official 9f8256607a Added the parameter message_thread_id to the method sendChatAction for sending chat actions to a specific message thread or a forum topic.
Added the parameter message_thread_id to the method sendChatAction for sending chat actions to a specific message thread or a forum topic.
2022-12-30 20:23:53 +04:00
coder2020official f297ad23c7 Added methods for topic management
Added the methods editGeneralForumTopic, closeGeneralForumTopic, reopenGeneralForumTopic, hideGeneralForumTopic, unhideGeneralForumTopic for managing the General topic in forums.
2022-12-30 20:19:50 +04:00
coder2020official a20a3ae321 topic events and write_access_allowed
Added the classes ForumTopicEdited, GeneralForumTopicHidden, GeneralForumTopicUnhidden, and WriteAccessAllowed and the fields forum_topic_edited, general_forum_topic_hidden, general_forum_topic_unhidden, and write_access_allowed to the class Message.
2022-12-30 20:07:38 +04:00
coder2020official 107f92314b icon_custom_emoji_id and name parameters made optional for edit_forum_topic
The parameters name and icon_custom_emoji_id of the method editForumTopic are now optional. If they are omitted, the existing values are kept.
2022-12-30 19:50:14 +04:00
coder2020official 9f5d9861a4 Added the field has_media_spoiler to the class Message.
Added the field has_media_spoiler to the class Message.
2022-12-30 19:41:46 +04:00
coder2020official 4537b237c8 has_spoiler for types.py
Added the field has_spoiler to the classes InputMediaPhoto, InputMediaVideo, and InputMediaAnimation.
2022-12-30 19:27:38 +04:00
coder2020official 4d11e97c25 has_spoiler parameter
Added the parameter has_spoiler to the methods sendPhoto, sendVideo, and sendAnimation.
2022-12-30 19:20:23 +04:00
coder2020official f0a1cefdda Added the field is_persistent to the class ReplyKeyboardMarkup
Added the field is_persistent to the class ReplyKeyboardMarkup, allowing to control when the keyboard is shown.
2022-12-30 19:08:37 +04:00
_run 24cd014410
Update README.md 2022-12-30 18:52:00 +04:00
Badiboy ba64180b5f
Merge pull request #1854 from Cub11k/master
Fixed typehints for reply markup in editing methods
2022-12-30 16:44:31 +03:00
Cub11k 3812fd05e3 Fixed typehints for reply markup in editing methods (async) 2022-12-30 14:04:12 +02:00
Cub11k 69afd7232e Fixed typehints for reply markup in editing methods 2022-12-30 14:02:02 +02:00
Badiboy 81600cf27e
Merge pull request #1849 from eternnoir/dependabot/pip/wheel-0.38.1
Bump wheel from 0.24.0 to 0.38.1
2022-12-30 00:02:27 +03:00
_run bb8023ecc6
Merge pull request #1852 from Cub11k/master
Fixed typehints for register_<any>_handler()
2022-12-28 22:14:50 +04:00
Cub11k a50a6e2e54 Fixed typehints for register_<any>_handler() 2022-12-28 20:00:06 +02:00
Badiboy 0329e5adb8
Merge pull request #1850 from ayitinya/patch-1
Update README.md
2022-12-27 09:17:26 +03:00
Rudy Ayitinya Sulley 2f25b56659
Update README.md
Adds a bot to Bots using this library list
2022-12-27 02:46:07 +00:00
dependabot[bot] 2aaab08517
Bump wheel from 0.24.0 to 0.38.1
Bumps [wheel](https://github.com/pypa/wheel) from 0.24.0 to 0.38.1.
- [Release notes](https://github.com/pypa/wheel/releases)
- [Changelog](https://github.com/pypa/wheel/blob/main/docs/news.rst)
- [Commits](https://github.com/pypa/wheel/compare/0.24.0...0.38.1)

---
updated-dependencies:
- dependency-name: wheel
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-26 19:49:24 +00:00
_run a6a22c351a
Merge pull request #1845 from Cub11k/master
Partly translated files: sync_version.po
2022-12-21 17:14:55 +04:00
Cub11k d211db90cf Update sync_version.po 2022-12-21 15:04:43 +02:00
_run f2c211616c
Merge pull request #1844 from coder2020official/master
✉️ Fixed escape_markdown: now it should escape { and } characters in a string as well.
2022-12-21 16:59:03 +04:00
_run c5e733a4c1
Escape both metachars 2022-12-20 23:47:12 +04:00
_run 925f7012f1
Update formatting.py 2022-12-20 23:44:32 +04:00
_run 625ae09573
Merge pull request #1839 from coder2020official/master
Fix bug with asyncwebhooks
2022-12-19 17:35:23 +04:00
coder2020official 5b279b7ad9 (A)SyncWebhookListener changes 2022-12-19 17:28:05 +04:00
_run 247cddf23d
Merge pull request #1831 from coder2020official/reloader_fix
Update reloader.py
2022-12-19 17:17:11 +04:00
_run 171172d12e
Update async_telebot.py 2022-12-19 17:12:15 +04:00
_run c3c12b93dd
Merge pull request #1832 from coder2020official/master
Fix bug related to get_user_profile_photos
2022-12-14 14:18:18 +04:00
_run add240adfd
Update asyncio_helper.py 2022-12-14 12:41:30 +04:00
_run 45fe2ea319
Update reloader.py 2022-12-13 18:44:41 +04:00
Badiboy 6373af78f3
Merge pull request #1824 from reddere/patch-3
fixing escape()
2022-12-03 16:48:16 +03:00
reddere 4ed460b137
Update util.py 2022-12-03 14:23:10 +01:00
reddere ae20cb9f31
Update util.py 2022-12-03 14:21:31 +01:00
reddere 669c18fdc0
update
updated "== None" to "is None" and adjusted the else statement
2022-12-03 14:11:07 +01:00
reddere 34acae9a59
fixing escape()
fixing escape() as replacing a None would throw an exception 'NoneType' object has no attribute 'replace'. useful in case of escaping a None string given from message.from_user.last_name as you dont know wether the user has a last name or not
2022-12-03 13:33:22 +01:00
Badiboy 109ae69f27
Merge pull request #1823 from Badiboy/master
Fixed register_next_step_handler_by_chat_id chat_id description
2022-12-03 00:01:57 +03:00
Badiboy 43abedbff7 Fixed register_next_step_handler_by_chat_id chat_id description 2022-12-02 23:59:59 +03:00
Badiboy 42d162f732
Merge pull request #1822 from Badiboy/master
Fix caption_entities miss in InputMediaXXX
2022-12-02 23:52:54 +03:00
Badiboy cd4dc899a1 Fix caption_entities miss in InputMediaXXX 2022-12-02 23:46:26 +03:00
_run 5066626692
Merge pull request #1818 from Cub11k/master
Translated to russian file: util.po
2022-12-01 12:46:16 +04:00
Konstantin Ostashenko e255d9cbab
Update docs/source/locales/ru/LC_MESSAGES/util.po
Co-authored-by: _run <khumogo1@gmail.com>
2022-11-30 23:12:33 +02:00
Konstantin Ostashenko 8e1c8a2742
Update docs/source/locales/ru/LC_MESSAGES/util.po
Co-authored-by: _run <khumogo1@gmail.com>
2022-11-30 23:12:25 +02:00
Cub11k e358abc1bd Update util.po 2022-11-30 21:07:46 +02:00
_run 42da2d1794
Merge pull request #1816 from Cub11k/master
Translated into russian file: formatting.po
2022-11-30 19:44:24 +04:00
Cub11k feaef2b2b8 Merge remote-tracking branch 'origin/master' 2022-11-30 17:33:28 +02:00
Cub11k 6cf60a3dcb Update formatting.po according to comments 2022-11-30 17:33:06 +02:00
Konstantin Ostashenko 91ff06eeba
Update docs/source/locales/ru/LC_MESSAGES/formatting.po
Co-authored-by: _run <khumogo1@gmail.com>
2022-11-30 16:49:46 +02:00
Cub1tor 1c2111d689 Update formatting.po 2022-11-29 20:19:25 +02:00
_run bf039df122
Merge pull request #1815 from coder2020official/master
Update install.po
2022-11-29 19:25:40 +04:00
_run 44309797d1
Update install.po 2022-11-29 19:21:05 +04:00
_run 8489383eb4
Merge pull request #1814 from abdullaev388/master
Translated into russian files:  install.po, quick_start.po
2022-11-29 19:12:54 +04:00
abdullaev388 848a2cc7ec
Update docs/source/locales/ru/LC_MESSAGES/install.po
Co-authored-by: _run <khumogo1@gmail.com>
2022-11-29 10:11:27 -05:00
abdullaev388 cc87dbce50
Update docs/source/locales/ru/LC_MESSAGES/install.po
Co-authored-by: _run <khumogo1@gmail.com>
2022-11-29 10:11:21 -05:00
abdullaev388 15f6bbeacb
Update docs/source/locales/ru/LC_MESSAGES/install.po
Co-authored-by: _run <khumogo1@gmail.com>
2022-11-29 10:09:48 -05:00
abdullaev388 29befa4d0c
Update install.po
translated into russian
2022-11-29 09:25:10 -05:00
abdullaev388 cce03dab78
Update quick_start.po
translated into russian
2022-11-29 09:21:24 -05:00
_run 7702d63fd7
Merge pull request #1813 from coder2020official/docs
Base of ru documentation added.
2022-11-29 17:39:30 +04:00
_run d636cdf88b
Update doc_req.txt 2022-11-29 17:37:16 +04:00
_run 06a28380d7
Update doc_req.txt 2022-11-29 17:33:42 +04:00
coder2020official d7e9d3accc Update conf.py 2022-11-29 14:59:17 +04:00
coder2020official 736c03fe84 Update conf.py 2022-11-29 14:49:32 +04:00
coder2020official 7502d26b1a Added locales 2022-11-29 14:45:51 +04:00
Badiboy b4d59fdf0a
Merge pull request #1812 from Badiboy/master
Bump version to 4.8.0 and update Python versions
2022-11-28 19:24:46 +03:00
Badiboy 8d723bdcb3 Python 3.6 removed, Python 3.11 added 2022-11-28 19:17:23 +03:00
Badiboy a169404a7c Bump version to 4.8.0 2022-11-28 19:14:07 +03:00
Badiboy 7a20017dfb
Merge pull request #1811 from coder2020official/continuehandling-fix
Continuehandling fix
2022-11-27 11:30:37 +03:00
_run 8d82b3d56b
Update async_telebot.py 2022-11-26 20:08:00 +04:00
_run 0759c8e081
Update __init__.py 2022-11-26 20:07:08 +04:00
_run 8992db1d24
Merge pull request #1808 from coder2020official/master
Fix #1804
2022-11-26 20:05:00 +04:00
_run deb2099396
Update types.py 2022-11-22 18:36:15 +04:00
_run 8a74198276
Merge pull request #1801 from coder2020official/master
Fixed bot api bug
2022-11-18 23:22:39 +04:00
_run 15bd5f991a
Update types.py 2022-11-18 23:21:06 +04:00
_run 25571b581c
Update types.py 2022-11-18 23:12:03 +04:00
Badiboy bf617ab8da
Merge pull request #1799 from Badiboy/master
content_type_media and content_type_service reviewed
2022-11-13 13:21:45 +03:00
Badiboy 74732f2eda content_type_media and content_type_service reviewed 2022-11-13 13:20:26 +03:00
Badiboy 0a79f7e4f3
Merge pull request #1783 from coder2020official/botapi-63
Bot API 6.3 Update
2022-11-13 12:39:38 +03:00
_run 8b735aa114
Update __init__.py 2022-11-13 13:34:54 +04:00
coder2020official ae1845f285 Added active_usernames and emoji_status_custom_emoji_id 2022-11-06 17:38:01 +04:00
coder2020official 0846852ea1 Added all necessary parameters
Added the parameter message_thread_id to the methods sendMessage, sendPhoto, sendVideo, sendAnimation, sendAudio, sendDocument, sendSticker, sendVideoNote, sendVoice, sendLocation, sendVenue, sendContact, sendPoll, sendDice, sendInvoice, sendGame, sendMediaGroup, copyMessage, forwardMessage to support sending of messages to a forum topic.
2022-11-06 17:31:49 +04:00
coder2020official 4825624d48 Added docs to types, added new methods
Added the methods createForumTopic, editForumTopic, closeForumTopic, reopenForumTopic, deleteForumTopic, unpinAllForumTopicMessages, and getForumTopicIconStickers for forum topic management.
2022-11-06 15:43:16 +04:00
coder2020official 876d679765 Added ForumTopic class and fixed previous classes by fixing de_json method. 2022-11-06 15:14:19 +04:00
coder2020official 7958d0dca7 Added can_manage_topics for promotechatmember
Added the parameter can_manage_topics to the method promoteChatMember.
2022-11-06 15:04:41 +04:00
coder2020official 4e2ea90db3 Added field can_manage_topics
Added the field can_manage_topics to the classes ChatAdministratorRights, ChatPermissions, ChatMemberAdministrator, and ChatMemberRestricted.
2022-11-06 15:00:20 +04:00
coder2020official 566aef1679 Fix wrong typehint for previous commit 2022-11-06 14:49:13 +04:00
Badiboy 2dad99ad95
Merge pull request #1761 from coder2020official/master
Extended exception handler behaviour for async
2022-11-06 09:23:02 +03:00
coder2020official f288470b43 Added the classes ForumTopicCreated, ForumTopicClosed, and ForumTopicReopened and the fields forum_topic_created, forum_topic_closed, and forum_topic_reopened to the class Message. Note that service messages about forum topic creation can't be deleted with the deleteMessage method.
Added the classes ForumTopicCreated, ForumTopicClosed, and ForumTopicReopened and the fields forum_topic_created, forum_topic_closed, and forum_topic_reopened to the class Message. Note that service messages about forum topic creation can't be deleted with the deleteMessage method.
2022-11-06 01:04:33 +04:00
coder2020official 475394d241 Added message_thread_id & is_topic_message 2022-11-05 23:23:00 +04:00
coder2020official 76f06cacfe Fix typo 2022-11-05 23:15:10 +04:00
coder2020official 77738b2537 Added is_forum 2022-11-05 23:14:37 +04:00
coder2020official 070479f7af Update async_telebot.py 2022-11-05 23:06:28 +04:00
coder2020official f1f18c6df2 Fix error description 2022-11-05 22:49:07 +04:00
_run 81c8ee5820
Update README.md 2022-11-05 22:20:11 +04:00
Badiboy 76a689d939
Merge pull request #1774 from batmanscode/master
fixes: `debug` removed from uvicorn #1767
2022-11-02 13:29:45 +03:00
batmanscode 92ecfdec48
fixes: `debug` removed from uvicorn #1767 2022-10-30 17:21:53 +00:00
Badiboy 20376168c1
Merge pull request #1772 from sijokun/master
Added example of running serverless on AWS Lambda
2022-10-29 12:02:31 +03:00
Yan Khachko 507d53efbd
Rename lambda_function.py to aws_lambda_function.py 2022-10-29 11:57:53 +03:00
Yan Khachko 1d8dc78c87
Added example of running serverless on AWS Lambda
Example of using of PyTelegramBotAPI in Amazon AWS Lambda
2022-10-29 01:18:52 +03:00
Badiboy ebec3bf5c1
Merge pull request #1762 from reddere/patch-1
Fixed InlineQueryResultVideo params in example.
2022-10-24 19:25:15 +03:00
reddere d11b9802da
Fixed InlineQueryResultVideo params in example.
Fixed InlineQueryResultVideo params in example. String "Video" was passed in stead of the thumbnail url, making the example not work, This has been tested working.
2022-10-24 16:02:59 +02:00
coder2020official 572f103db7 Extended exception handler behaviour for async 2022-10-22 21:48:29 +04:00
Badiboy 231371f1f8
Merge pull request #1759 from Badiboy/master
Bump version to 4.7.1
2022-10-21 10:58:23 +03:00
Badiboy 623d8b27ec Bump version to 4.7.1 2022-10-21 10:18:47 +03:00
Badiboy 31c3a2b2a3
Merge pull request #1742 from byehack/ContinueHandling
Support ContinueHandling
2022-10-11 19:03:44 +03:00
_run c45af810f9
Updated docstrings for ContinueHandling 2022-10-11 19:15:38 +04:00
_run 81f090cce6
Update asyncio_handler_backends.py 2022-10-11 19:15:01 +04:00
_run 5d16b8bd4a
Create continue_handling.py 2022-10-11 19:13:10 +04:00
_run 0fecf46201
Create continue_handling.py 2022-10-11 19:09:59 +04:00
_run 982e642c73
Update telebot/handler_backends.py 2022-10-11 19:05:55 +04:00
byehack 97bca49c00
ContinueHandling on asyncio_handler_backends 2022-10-09 02:28:05 +03:30
Badiboy e0ee087162
Merge pull request #1749 from Badiboy/master
Check CUSTOM_REQUEST_SENDER before RETRY_xxx.
2022-10-08 23:43:44 +03:00
Badiboy 620b1364a6 Check CUSTOM_REQUEST_SENDER before RETRY_xxx. 2022-10-08 23:41:41 +03:00
Badiboy c561cf3076
Merge pull request #1748 from coder2020official/master
Added warning for non_stop=False
2022-10-08 23:24:58 +03:00
coder2020official b3953d6249 ℹ️ Better description 2022-10-08 23:03:04 +04:00
coder2020official 2d7170feee Added warning for non_stop=False 2022-10-08 22:35:22 +04:00
Badiboy 0ca8007633
Merge pull request #1747 from coder2020official/master
Update __init__.py
2022-10-07 20:57:49 +03:00
_run c541533762
Update __init__.py 2022-10-07 21:50:51 +04:00
byehack 4798c26188
improve code quality 2022-10-02 12:05:20 +03:30
byehack 30aaf8d0f1
Support ContinueHandling 2022-10-02 03:27:06 +03:30
Badiboy 82ad37fed8
Merge pull request #1693 from coder2020official/conflicts
Logging improvements(still not 100%), file restarts on file changes(needs tests), and more
2022-10-01 22:30:49 +03:00
coder2020official 2d1f39085d Improved code readability x 2 2022-10-01 22:34:49 +04:00
coder2020official b523cec22f Improved code readability 2022-10-01 22:32:41 +04:00
coder2020official 27e0197855 Added examples and made it possible to specify --path path for path 2022-10-01 21:28:53 +04:00
coder2020official ea69b8093d Added some notes 2022-10-01 21:15:24 +04:00
coder2020official 04ff428bba Added option to specify path to watch 2022-10-01 21:02:40 +04:00
coder2020official eb576d83fb Fixed a bug, made improvements in reload system
Didn't test that much, there is still some stuff to do
2022-09-30 23:22:21 +04:00
_run d3080b6d4e
Merge branch 'master' into conflicts 2022-09-30 22:53:19 +04:00
Badiboy 7c9b01b10a
Merge pull request #1722 from Badiboy/master
Handlers and Middlewares processing union
2022-09-24 22:16:33 +03:00
Badiboy b3993bb019 Merge remote-tracking branch 'upstream/master' 2022-09-24 22:14:45 +03:00
Badiboy 36b889feab
Merge pull request #1736 from AntonGlyzin/antonglyzin-shopbotlist
Added a new bot to the list
2022-09-24 16:06:33 +03:00
Anton d943f40643 Added a new bot to the list 2022-09-24 15:33:11 +03:00
_run dafafd2ad2
Merge pull request #1735 from coder2020official/class_params
⚙️ Added some frequent parameters to classes(see full list)
2022-09-23 22:06:09 +04:00
coder2020official e002484a9b ⚙️ Added some frequent parameters to classes(see full list)
Added:
- disable_web_page_preview
- disable_notification
- protect_content
- allow_sending_without_reply
2022-09-23 21:52:40 +04:00
Badiboy 52e09637c2 Fix: do not call handler in one more task 2022-09-17 23:17:07 +03:00
Badiboy e7a96ec2ed Rename also in Async 2022-09-17 14:09:05 +03:00
Badiboy 598de25b6d Rename _check_middlewares to _get_middlewares 2022-09-17 12:55:55 +03:00
_run b841fc10ed
Merge pull request #1723 from byehack/patch-1
don't block loop
2022-09-17 13:42:57 +04:00
byehack c14760d81c
don't block loop 2022-09-17 13:58:28 +04:30
Badiboy da639dd1f6 Handlers and Middlewares processing union
Call for handlers now union in a single function for future extension.

Plus minor fixes in storages.
2022-09-17 11:57:12 +03:00
_run 96e137f5e6
Update setup.py 2022-09-16 22:39:40 +04:00
Badiboy 8d9dfcfac8
Merge pull request #1707 from S1RANN/master
raise other exceptions in antiflood function
2022-09-13 17:59:30 +03:00
_run a1c77db236
Merge pull request #1710 from coder2020official/bugfixes
Fixed difference between request_timeout and timeout.
2022-09-10 20:48:30 +04:00
coder2020official 4f97b26e81 Update asyncio_helper.py 2022-09-10 20:37:13 +04:00
coder2020official 0028feb4c5 Update asyncio_helper.py 2022-09-10 20:14:48 +04:00
orocane a06b4a1e9c raise other exceptions in antiflood 2022-09-10 21:46:16 +08:00
coder2020official da5084f53c Update asyncio_helper.py 2022-09-10 14:36:56 +04:00
coder2020official 2f8d878f06 Fixed difference between request_timeout and timeout.
getUpdates parameter may contain 2 parameters: request_timeout & timeout. other methods may contain timeout parameter that should be applied to ClientTimeout.
2022-09-10 14:34:56 +04:00
orocane 783beb165b raise other exceptions in antiflood 2022-09-10 15:59:40 +08:00
_run 4fd01e3ac8
Merge pull request #1703 from coder2020official/downloadfile
Fix #1702
2022-09-09 21:09:25 +04:00
_run b4c28de104
Update asyncio_helper.py 2022-09-07 20:44:39 +04:00
_run de344bd5e0
Merge pull request #1701 from coder2020official/states
#1699 fixed
2022-09-06 18:16:06 +04:00
_run e3a4fdff9a
Update asyncio_filters.py 2022-09-06 18:12:11 +04:00
_run 71d3ec8b42
Changed user id and chat id 2022-09-06 18:11:40 +04:00
coder2020official 1b1d6c8239 Improved asyncio helper's logger 2022-08-30 21:26:56 +04:00
coder2020official 9216f15c16 Logs, file restarts, loggers to async
Added colorful logs, file restarts on changes, improved logger, added cached version of user-bot to async
2022-08-30 21:26:41 +04:00
coder2020official 0f7ab0d05f Added colorful logs, file restarts on changes to sync 2022-08-30 21:25:41 +04:00
coder2020official e0ffe0b4f5 Added reloader to ext 2022-08-30 21:24:54 +04:00
Badiboy f4c5dd0d22
Merge pull request #1691 from ananthb/master
Starlette ASGI example
2022-08-30 15:55:28 +03:00
Ananth Bhaskararaman e4179ea65f
Add SSL cert 2022-08-30 17:27:43 +05:30
Ananth Bhaskararaman d7770bf670
Starlette ASGI example 2022-08-30 17:05:56 +05:30
_run 095bf03227
Merge pull request #1688 from ananthb/patch-1
Import aioredis from redis module too
2022-08-30 12:28:18 +04:00
_run 85bd174fdc
Update redis_storage.py 2022-08-30 12:26:34 +04:00
Ananth Bhaskararaman b86c38367a
Import aioredis from redis module too
aioredis is available in redis-py as of version 4.2.0rc1: https://github.com/aio-libs/aioredis-py#-aioredis-is-now-in-redis-py-420rc1-
Try importing from the new package as well.
2022-08-28 17:32:56 +05:30
Badiboy b8214d32d5
Merge pull request #1679 from Badiboy/master
Code simplify and sync/async unificatiion
2022-08-22 12:20:36 +03:00
Badiboy f4e66f6807 Added traceback for handlers exception 2022-08-21 22:27:02 +03:00
Badiboy b1a4136603 Code simplify and sync/async unificatiion 2022-08-21 20:32:37 +03:00
Badiboy 3d97b08289
Merge pull request #1678 from coder2020official/master
Fixed bug with searching a new handler after the execution of handler
2022-08-21 19:38:59 +03:00
_run 3d2576ca24 Fixed bug with searching a new handler after the execution of handler 2022-08-21 20:42:55 +05:00
Badiboy b2d2ab5c33
Merge pull request #1675 from coder2020official/master
Fixed #1650
2022-08-17 00:38:59 +03:00
_run c9a732e3dd
Merge branch 'eternnoir:master' into master 2022-08-16 21:39:55 +05:00
_run 01be1fb583 Fixes #1650 2022-08-16 21:39:20 +05:00
Badiboy 7b95874627
Merge pull request #1672 from Badiboy/master
Typo fix
2022-08-16 17:34:57 +03:00
Badiboy 426f9f3787 Typo fix
and minor code opt
2022-08-16 17:12:50 +03:00
57 changed files with 42544 additions and 1198 deletions

View File

@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ '3.6','3.7','3.8','3.9', '3.10', 'pypy-3.7', 'pypy-3.8', 'pypy-3.9']
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11', 'pypy-3.7', 'pypy-3.8', 'pypy-3.9']
name: ${{ matrix.python-version }} and tests
steps:
- uses: actions/checkout@v2

22
.readthedocs.yaml Normal file
View File

@ -0,0 +1,22 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.9"
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# We recommend specifying your dependencies to enable reproducible builds:
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: docs/requirements.txt

View File

@ -4,6 +4,7 @@ python:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "pypy3"
install: "pip install -r requirements.txt"
script:

View File

@ -2,7 +2,6 @@
[![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)
[![Documentation Status](https://readthedocs.org/projects/pytba/badge/?version=latest)](https://pytba.readthedocs.io/en/latest/?badge=latest)
[![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/)
[![PyPi status](https://img.shields.io/pypi/status/pytelegrambotapi.svg?style=flat-square)](https://pypi.python.org/pypi/pytelegrambotapi)
@ -11,9 +10,10 @@
<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">Both synchronous and asynchronous.</p>
## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#august-12-2022">6.2</a>!
## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#april-21-2023">6.7</a>!
<h2><a href='https://pytba.readthedocs.io/en/latest/index.html'>Official documentation</a></h2>
<h2><a href='https://pytba.readthedocs.io/ru/latest/index.html'>Official ru documentation</a></h2>
## Contents
@ -69,7 +69,7 @@
## Getting started
This API is tested with Python 3.6-3.10 and Pypy 3.
This API is tested with Python 3.7-3.11 and Pypy 3.
There are two ways to install the library:
* Installation using pip (a Python package manager):
@ -265,7 +265,7 @@ def test_callback(call): # <- passes a CallbackQuery type object to your functio
#### Shipping Query Handler
Handle shipping queries
`@bot.shipping_query_handeler() # <- passes a ShippingQuery type object to your function`
`@bot.shipping_query_handler() # <- passes a ShippingQuery type object to your function`
#### Pre Checkout Query Handler
Handle pre checkoupt queries
@ -877,6 +877,7 @@ Here are some examples of template:
* [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.
* [Diccionario de la RAE](https://t.me/dleraebot) ([source](https://github.com/studentenherz/dleraebot)) This bot lets you find difinitions of words in Spanish using [RAE's dictionary](https://dle.rae.es/). It features direct message and inline search.
* [remoteTelegramShell](https://github.com/EnriqueMoran/remoteTelegramShell) by [EnriqueMoran](https://github.com/EnriqueMoran). Control your LinuxOS computer through Telegram.
* [Commerce Telegram Bot](https://github.com/ayitinya/commerce-telegram-bot/). Make purchases of items in a store with an Admin panel for data control and notifications.
* [Pyfram-telegram-bot](https://github.com/skelly37/pyfram-telegram-bot) Query wolframalpha.com and make use of its API through Telegram.
* [TranslateThisVideoBot](https://gitlab.com/WuerfelDev/translatethisvideo) This Bot can understand spoken text in videos and translate it to English
* [Zyprexa](https://t.me/mathemathicsBot) ([source](https://github.com/atif5/zyprexa)) Zyprexa can solve, help you solve any mathematical problem you encounter and convert your regular mathematical expressions into beautiful imagery using LaTeX.
@ -885,5 +886,11 @@ Here are some examples of template:
* [Gugumoe-bot](http://t.me/gugumoe_bot) ([source](https://github.com/GooGuJiang/Gugumoe-bot)) by [咕谷酱](https://gmoe.cc) GuXiaoJiang is a multi-functional robot, such as OSU game information query, IP test, animation screenshot search and other functions.
* [Feedback-bot](https://github.com/coder2020official/feedbackbot) A feedback bot for user-admin communication. Made on AsyncTeleBot, using [template](https://github.com/coder2020official/asynctelebot_template).
* [TeleServ](https://github.com/ablakely/TeleServ) by [ablakely](https://github.com/ablakely) This is a Telegram to IRC bridge which links as an IRC server and makes Telegram users appear as native IRC users.
* [Simple Store Bot](https://github.com/AntonGlyzin/myshopbot) by [Anton Glyzin](https://github.com/AntonGlyzin) This is a simple telegram-store with an admin panel. Designed according to a template.
* [Media Rating Bot](https://t.me/mediaratingbot) ([source](https://github.com/CommanderCRM/MediaRatingBot))by [CommanderCRM](https://github.com/CommanderCRM). This bot aggregates media (movies, TV series, etc.) ratings from IMDb, Rotten Tomatoes, Metacritic, TheMovieDB, FilmAffinity and also provides number of votes of said media on IMDb.
* [Spot Seek Bot](https://t.me/SpotSeekBot) ([source](https://github.com/arashnm80/spot-seek-bot)) by [Arashnm80](https://github.com/arashnm80). This is a free & open source telegram bot for downloading tracks, albums or playlists from spotify.
* [CalendarIT Bot](https://t.me/calendarit_bot) ([source](https://github.com/codebyzen/CalendarIT_Telegram_Bot))by [CodeByZen](https://github.com/codebyzen). A simple, but extensible Python Telegram bot, can post acquainted with what is happening today, tomorrow or what happened 20 years ago to channel.
* [DownloadMusicBOT](https://github.com/fcoagz/DownloadMusicBOT) by *Francisco Griman* - It is a simple bot that downloads audio from YouTube videos on Telegram.
* [AwesomeChatGPTBot](https://github.com/Kourva/AwesomeChatGPTBot) - Simple ChatGTP-3.5 bot. It is FREE and can remember chat history for a while With pre-defined roles!
**Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.**

View File

@ -18,11 +18,11 @@
# -- Project information -----------------------------------------------------
project = 'pyTelegramBotAPI Documentation'
copyright = '2022, coder2020official'
copyright = '2022-2023, coder2020official'
author = 'coder2020official'
# The full version, including alpha/beta/rc tags
release = '4.7.0'
release = '4.12.0'
# -- General configuration ---------------------------------------------------
@ -68,3 +68,5 @@ html_theme_options = {
"light_logo": "logo.png",
"dark_logo": "logo2.png",
}
locale_dirs = ["locales/"]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,127 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../calldata.rst:4
msgid "Callback data factory"
msgstr ""
#: ../../calldata.rst:6
msgid "Callback data factory in pyTelegramBotAPI"
msgstr ""
#: ../../calldata.rst:6
msgid ""
"ptba, pytba, pyTelegramBotAPI, callbackdatafactory, guide, callbackdata, "
"factory"
msgstr ""
#: ../../calldata.rst:12
msgid "callback\\_data file"
msgstr ""
#: of telebot.callback_data:1
msgid "Callback data factory's file."
msgstr ""
#: of telebot.callback_data.CallbackData:1
#: telebot.callback_data.CallbackDataFilter:1
msgid "Bases: :py:class:`object`"
msgstr ""
#: of telebot.callback_data.CallbackData:1
msgid "Callback data factory This class will help you to work with CallbackQuery"
msgstr ""
#: of telebot.callback_data.CallbackData.filter:1
msgid "Generate filter"
msgstr ""
#: of telebot.callback_data.CallbackData.filter
#: telebot.callback_data.CallbackData.new
#: telebot.callback_data.CallbackData.parse
#: telebot.callback_data.CallbackDataFilter.check
msgid "Parameters"
msgstr ""
#: of telebot.callback_data.CallbackData.filter:3
msgid "specified named parameters will be checked with CallbackQuery.data"
msgstr ""
#: of telebot.callback_data.CallbackData.filter
#: telebot.callback_data.CallbackData.new
#: telebot.callback_data.CallbackData.parse
#: telebot.callback_data.CallbackDataFilter.check
msgid "Returns"
msgstr ""
#: of telebot.callback_data.CallbackData.filter:4
msgid "CallbackDataFilter class"
msgstr ""
#: of telebot.callback_data.CallbackData.new:1
msgid "Generate callback data"
msgstr ""
#: of telebot.callback_data.CallbackData.new:3
msgid "positional parameters of CallbackData instance parts"
msgstr ""
#: of telebot.callback_data.CallbackData.new:4
msgid "named parameters"
msgstr ""
#: of telebot.callback_data.CallbackData.new:5
msgid "str"
msgstr ""
#: of telebot.callback_data.CallbackData.parse:1
msgid "Parse data from the callback data"
msgstr ""
#: of telebot.callback_data.CallbackData.parse:3
msgid ""
"string, use to telebot.types.CallbackQuery to parse it from string to a "
"dict"
msgstr ""
#: of telebot.callback_data.CallbackData.parse:4
msgid "dict parsed from callback data"
msgstr ""
#: of telebot.callback_data.CallbackDataFilter:1
msgid "Filter for CallbackData."
msgstr ""
#: of telebot.callback_data.CallbackDataFilter.check:1
msgid "Checks if query.data appropriates to specified config"
msgstr ""
#: of telebot.callback_data.CallbackDataFilter.check:3
msgid "telebot.types.CallbackQuery"
msgstr ""
#: of telebot.callback_data.CallbackDataFilter.check:6
msgid "True if query.data appropriates to specified config"
msgstr ""
#: of telebot.callback_data.CallbackDataFilter.check
msgid "Return type"
msgstr ""

View File

@ -0,0 +1,251 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../formatting.rst:3
msgid "Formatting options"
msgstr ""
#: ../../formatting.rst:5
msgid "Formatting options in pyTelegramBotAPI"
msgstr ""
#: ../../formatting.rst:5
msgid "html, markdown, parse_mode, formatting, ptba, pytba, pyTelegramBotAPI"
msgstr ""
#: of telebot.formatting:1
msgid "Markdown & HTML formatting functions."
msgstr ""
#: of telebot.formatting.escape_html:1
msgid "Escapes HTML characters in a string of HTML."
msgstr ""
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
#: telebot.formatting.format_text telebot.formatting.hbold
#: telebot.formatting.hcode telebot.formatting.hide_link
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
#: telebot.formatting.hunderline telebot.formatting.mbold
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
#: telebot.formatting.munderline
msgid "Parameters"
msgstr ""
#: of telebot.formatting.escape_html:3
msgid "The string of HTML to escape."
msgstr ""
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
#: telebot.formatting.format_text telebot.formatting.hbold
#: telebot.formatting.hcode telebot.formatting.hide_link
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
#: telebot.formatting.hunderline telebot.formatting.mbold
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
#: telebot.formatting.munderline
msgid "Returns"
msgstr ""
#: of telebot.formatting.escape_html:6 telebot.formatting.escape_markdown:8
msgid "The escaped string."
msgstr ""
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
#: telebot.formatting.format_text telebot.formatting.hbold
#: telebot.formatting.hcode telebot.formatting.hide_link
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
#: telebot.formatting.hunderline telebot.formatting.mbold
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
#: telebot.formatting.munderline
msgid "Return type"
msgstr ""
#: of telebot.formatting.escape_html:7 telebot.formatting.escape_markdown:9
#: telebot.formatting.format_text:17 telebot.formatting.hbold:10
#: telebot.formatting.hcode:10 telebot.formatting.hide_link:7
#: telebot.formatting.hitalic:10 telebot.formatting.hlink:13
#: telebot.formatting.hpre:10 telebot.formatting.hspoiler:10
#: telebot.formatting.hstrikethrough:10 telebot.formatting.hunderline:10
#: telebot.formatting.mbold:10 telebot.formatting.mcode:10
#: telebot.formatting.mitalic:10 telebot.formatting.mlink:13
#: telebot.formatting.mspoiler:10 telebot.formatting.mstrikethrough:10
#: telebot.formatting.munderline:10
msgid ":obj:`str`"
msgstr ""
#: of telebot.formatting.escape_markdown:1
msgid "Escapes Markdown characters in a string of Markdown."
msgstr ""
#: of telebot.formatting.escape_markdown:3
msgid "Credits to: simonsmh"
msgstr ""
#: of telebot.formatting.escape_markdown:5
msgid "The string of Markdown to escape."
msgstr ""
#: of telebot.formatting.format_text:1
msgid "Formats a list of strings into a single string."
msgstr ""
#: of telebot.formatting.format_text:10
msgid "Strings to format."
msgstr ""
#: of telebot.formatting.format_text:13
msgid "The separator to use between each string."
msgstr ""
#: of telebot.formatting.format_text:16 telebot.formatting.hbold:9
#: telebot.formatting.hcode:9 telebot.formatting.hitalic:9
#: telebot.formatting.hlink:12 telebot.formatting.hpre:9
#: telebot.formatting.hspoiler:9 telebot.formatting.hstrikethrough:9
#: telebot.formatting.hunderline:9 telebot.formatting.mbold:9
#: telebot.formatting.mcode:9 telebot.formatting.mitalic:9
#: telebot.formatting.mlink:12 telebot.formatting.mspoiler:9
#: telebot.formatting.mstrikethrough:9 telebot.formatting.munderline:9
msgid "The formatted string."
msgstr ""
#: of telebot.formatting.hbold:1
msgid "Returns an HTML-formatted bold string."
msgstr ""
#: of telebot.formatting.hbold:3 telebot.formatting.mbold:3
msgid "The string to bold."
msgstr ""
#: of telebot.formatting.hbold:6 telebot.formatting.hcode:6
#: telebot.formatting.hitalic:6 telebot.formatting.hlink:9
#: telebot.formatting.hpre:6 telebot.formatting.hspoiler:6
#: telebot.formatting.hstrikethrough:6 telebot.formatting.hunderline:6
#: telebot.formatting.mbold:6 telebot.formatting.mcode:6
#: telebot.formatting.mitalic:6 telebot.formatting.mlink:9
#: telebot.formatting.mspoiler:6 telebot.formatting.mstrikethrough:6
#: telebot.formatting.munderline:6
msgid "True if you need to escape special characters. Defaults to True."
msgstr ""
#: of telebot.formatting.hcode:1
msgid "Returns an HTML-formatted code string."
msgstr ""
#: of telebot.formatting.hcode:3 telebot.formatting.mcode:3
msgid "The string to code."
msgstr ""
#: of telebot.formatting.hide_link:1
msgid "Hide url of an image."
msgstr ""
#: of telebot.formatting.hide_link:3
msgid "The url of the image."
msgstr ""
#: of telebot.formatting.hide_link:6
msgid "The hidden url."
msgstr ""
#: of telebot.formatting.hitalic:1
msgid "Returns an HTML-formatted italic string."
msgstr ""
#: of telebot.formatting.hitalic:3 telebot.formatting.mitalic:3
msgid "The string to italicize."
msgstr ""
#: of telebot.formatting.hlink:1
msgid "Returns an HTML-formatted link string."
msgstr ""
#: of telebot.formatting.hlink:3 telebot.formatting.mlink:3
msgid "The string to link."
msgstr ""
#: of telebot.formatting.hlink:6 telebot.formatting.mlink:6
msgid "The URL to link to."
msgstr ""
#: of telebot.formatting.hpre:1
msgid "Returns an HTML-formatted preformatted string."
msgstr ""
#: of telebot.formatting.hpre:3
msgid "The string to preformatted."
msgstr ""
#: of telebot.formatting.hspoiler:1
msgid "Returns an HTML-formatted spoiler string."
msgstr ""
#: of telebot.formatting.hspoiler:3 telebot.formatting.mspoiler:3
msgid "The string to spoiler."
msgstr ""
#: of telebot.formatting.hstrikethrough:1
msgid "Returns an HTML-formatted strikethrough string."
msgstr ""
#: of telebot.formatting.hstrikethrough:3 telebot.formatting.mstrikethrough:3
msgid "The string to strikethrough."
msgstr ""
#: of telebot.formatting.hunderline:1
msgid "Returns an HTML-formatted underline string."
msgstr ""
#: of telebot.formatting.hunderline:3 telebot.formatting.munderline:3
msgid "The string to underline."
msgstr ""
#: of telebot.formatting.mbold:1
msgid "Returns a Markdown-formatted bold string."
msgstr ""
#: of telebot.formatting.mcode:1
msgid "Returns a Markdown-formatted code string."
msgstr ""
#: of telebot.formatting.mitalic:1
msgid "Returns a Markdown-formatted italic string."
msgstr ""
#: of telebot.formatting.mlink:1
msgid "Returns a Markdown-formatted link string."
msgstr ""
#: of telebot.formatting.mspoiler:1
msgid "Returns a Markdown-formatted spoiler string."
msgstr ""
#: of telebot.formatting.mstrikethrough:1
msgid "Returns a Markdown-formatted strikethrough string."
msgstr ""
#: of telebot.formatting.munderline:1
msgid "Returns a Markdown-formatted underline string."
msgstr ""

View File

@ -0,0 +1,120 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../index.rst:8
msgid "Welcome to pyTelegramBotAPI's documentation!"
msgstr ""
#: ../../index.rst:10
msgid "Official documentation of pyTelegramBotAPI"
msgstr ""
#: ../../index.rst:10
msgid "ptba, pytba, pyTelegramBotAPI, documentation, guide"
msgstr ""
#: ../../index.rst:17
msgid "TeleBot"
msgstr ""
#: ../../index.rst:18
msgid ""
"TeleBot is synchronous and asynchronous implementation of `Telegram Bot "
"API <https://core.telegram.org/bots/api>`_."
msgstr ""
#: ../../index.rst:21
msgid "Chats"
msgstr ""
#: ../../index.rst:22
msgid ""
"English chat: `Private chat "
"<https://telegram.me/joinchat/Bn4ixj84FIZVkwhk2jag6A>`__"
msgstr ""
#: ../../index.rst:24
msgid ""
"Russian chat: `@pytelegrambotapi_talks_ru "
"<https://t.me/pytelegrambotapi_talks_ru>`__"
msgstr ""
#: ../../index.rst:26
msgid "News: `@pyTelegramBotAPI <https://t.me/pytelegrambotapi>`__"
msgstr ""
#: ../../index.rst:28
msgid "Pypi: `Pypi <https://pypi.org/project/pyTelegramBotAPI/>`__"
msgstr ""
#: ../../index.rst:30
msgid ""
"Source: `Github repository "
"<https://github.com/eternnoir/pyTelegramBotAPI>`__"
msgstr ""
#: ../../index.rst:33
msgid "Some features:"
msgstr ""
#: ../../index.rst:34
msgid "Easy to learn and use."
msgstr ""
#: ../../index.rst:36
msgid "Easy to understand."
msgstr ""
#: ../../index.rst:38
msgid "Both sync and async."
msgstr ""
#: ../../index.rst:40
msgid "Examples on features."
msgstr ""
#: ../../index.rst:42
msgid "States"
msgstr ""
#: ../../index.rst:44
msgid "And more..."
msgstr ""
#: ../../index.rst:47
msgid "Content"
msgstr ""
#: ../../index.rst:63
msgid "Indices and tables"
msgstr ""
#: ../../index.rst:65
msgid ":ref:`genindex`"
msgstr ""
#: ../../index.rst:66
msgid ":ref:`modindex`"
msgstr ""
#: ../../index.rst:67
msgid ":ref:`search`"
msgstr ""

View File

@ -0,0 +1,58 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../install.rst:3
msgid "Installation Guide"
msgstr ""
#: ../../install.rst:5
msgid "Installation of pyTelegramBotAPI"
msgstr ""
#: ../../install.rst:5
msgid "ptba, pytba, pyTelegramBotAPI, installation, guide"
msgstr ""
#: ../../install.rst:11
msgid "Using PIP"
msgstr ""
#: ../../install.rst:17
msgid "Using pipenv"
msgstr ""
#: ../../install.rst:23
msgid "By cloning repository"
msgstr ""
#: ../../install.rst:31
msgid "Directly using pip"
msgstr ""
#: ../../install.rst:37
msgid "It is generally recommended to use the first option."
msgstr ""
#: ../../install.rst:39
msgid ""
"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:"
msgstr ""

View File

@ -0,0 +1,40 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../quick_start.rst:4
msgid "Quick start"
msgstr ""
#: ../../quick_start.rst:6
msgid "Quickstart guide"
msgstr ""
#: ../../quick_start.rst:6
msgid "ptba, pytba, pyTelegramBotAPI, quickstart, guide"
msgstr ""
#: ../../quick_start.rst:11
msgid "Synchronous TeleBot"
msgstr ""
#: ../../quick_start.rst:16
msgid "Asynchronous TeleBot"
msgstr ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,355 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-08 23:07+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../source/util.rst:3
msgid "Utils"
msgstr ""
#: ../../source/util.rst:5
msgid "Utils in pyTelegramBotAPI"
msgstr ""
#: ../../source/util.rst:5
msgid "ptba, pytba, pyTelegramBotAPI, utils, guide"
msgstr ""
#: ../../source/util.rst:11
msgid "util file"
msgstr ""
#: of telebot.util.antiflood:1
msgid ""
"Use this function inside loops in order to avoid getting TooManyRequests "
"error. Example:"
msgstr ""
#: of telebot.service_utils.is_bytes telebot.service_utils.is_dict
#: telebot.service_utils.is_pil_image telebot.util.antiflood
#: telebot.util.escape telebot.util.extract_arguments
#: telebot.util.extract_command telebot.util.is_command
#: telebot.util.parse_web_app_data telebot.util.quick_markup
#: telebot.util.smart_split telebot.util.split_string telebot.util.user_link
#: telebot.util.validate_web_app_data telebot.util.webhook_google_functions
msgid "Parameters"
msgstr ""
#: of telebot.util.antiflood:10
msgid "The function to call"
msgstr ""
#: of telebot.util.antiflood:13
msgid "Number of retries to send"
msgstr ""
#: of telebot.util.antiflood:16
msgid "The arguments to pass to the function"
msgstr ""
#: of telebot.util.antiflood:19
msgid "The keyword arguments to pass to the function"
msgstr ""
#: of telebot.service_utils.generate_random_token
#: telebot.service_utils.is_bytes telebot.service_utils.is_dict
#: telebot.service_utils.is_pil_image telebot.util.antiflood
#: telebot.util.escape telebot.util.extract_arguments
#: telebot.util.extract_command telebot.util.is_command
#: telebot.util.parse_web_app_data telebot.util.quick_markup
#: telebot.util.smart_split telebot.util.split_string telebot.util.user_link
#: telebot.util.validate_web_app_data telebot.util.webhook_google_functions
msgid "Returns"
msgstr ""
#: of telebot.util.antiflood:22
msgid "None"
msgstr ""
#: of telebot.service_utils.chunks:1
msgid "Yield successive n-sized chunks from lst."
msgstr ""
#: ../../docstring of telebot.util.content_type_media:1
msgid "Contains all media content types."
msgstr ""
#: ../../docstring of telebot.util.content_type_service:1
msgid "Contains all service content types such as `User joined the group`."
msgstr ""
#: of telebot.util.escape:1
msgid ""
"Replaces the following chars in `text` ('&' with '&amp;', '<' with '&lt;'"
" and '>' with '&gt;')."
msgstr ""
#: of telebot.util.escape:3
msgid "the text to escape"
msgstr ""
#: of telebot.util.escape:4
msgid "the escaped text"
msgstr ""
#: of telebot.util.extract_arguments:1
msgid "Returns the argument after the command."
msgstr ""
#: of telebot.util.extract_arguments:3 telebot.util.extract_command:4
msgid "Examples:"
msgstr ""
#: of telebot.util.extract_arguments:10
msgid "String to extract the arguments from a command"
msgstr ""
#: of telebot.util.extract_arguments:13
msgid "the arguments if `text` is a command (according to is_command), else None."
msgstr ""
#: of telebot.service_utils.generate_random_token
#: telebot.service_utils.is_bytes telebot.service_utils.is_dict
#: telebot.service_utils.is_pil_image telebot.util.extract_arguments
#: telebot.util.extract_command telebot.util.is_command
#: telebot.util.quick_markup telebot.util.smart_split telebot.util.split_string
#: telebot.util.user_link
msgid "Return type"
msgstr ""
#: of telebot.util.extract_arguments:14 telebot.util.extract_command:16
msgid ":obj:`str` or :obj:`None`"
msgstr ""
#: of telebot.util.extract_command:1
msgid ""
"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."
msgstr ""
#: of telebot.util.extract_command:12
msgid "String to extract the command from"
msgstr ""
#: of telebot.util.extract_command:15
msgid "the command if `text` is a command (according to is_command), else None."
msgstr ""
#: of telebot.service_utils.generate_random_token:1
msgid ""
"Generates a random token consisting of letters and digits, 16 characters "
"long."
msgstr ""
#: of telebot.service_utils.generate_random_token:3
msgid "a random token"
msgstr ""
#: of telebot.service_utils.generate_random_token:4 telebot.util.user_link:22
msgid ":obj:`str`"
msgstr ""
#: of telebot.service_utils.is_bytes:1
msgid "Returns True if the given object is a bytes object."
msgstr ""
#: of telebot.service_utils.is_bytes:3 telebot.service_utils.is_dict:3
#: telebot.service_utils.is_pil_image:3
msgid "object to be checked"
msgstr ""
#: of telebot.service_utils.is_bytes:6
msgid "True if the given object is a bytes object."
msgstr ""
#: of telebot.service_utils.is_bytes:7 telebot.service_utils.is_dict:7
#: telebot.service_utils.is_pil_image:7 telebot.util.is_command:7
msgid ":obj:`bool`"
msgstr ""
#: of telebot.util.is_command:1
msgid ""
"Checks if `text` is a command. Telegram chat commands start with the '/' "
"character."
msgstr ""
#: of telebot.util.is_command:3
msgid "Text to check."
msgstr ""
#: of telebot.util.is_command:6
msgid "True if `text` is a command, else False."
msgstr ""
#: of telebot.service_utils.is_dict:1
msgid "Returns True if the given object is a dictionary."
msgstr ""
#: of telebot.service_utils.is_dict:6
msgid "True if the given object is a dictionary."
msgstr ""
#: of telebot.service_utils.is_pil_image:1
msgid "Returns True if the given object is a PIL.Image.Image object."
msgstr ""
#: of telebot.service_utils.is_pil_image:6
msgid "True if the given object is a PIL.Image.Image object."
msgstr ""
#: of telebot.service_utils.is_string:1
msgid "Returns True if the given object is a string."
msgstr ""
#: of telebot.util.parse_web_app_data:1
msgid "Parses web app data."
msgstr ""
#: of telebot.util.parse_web_app_data:3 telebot.util.validate_web_app_data:3
msgid "The bot token"
msgstr ""
#: of telebot.util.parse_web_app_data:6 telebot.util.validate_web_app_data:6
msgid "The raw init data"
msgstr ""
#: of telebot.util.parse_web_app_data:9 telebot.util.validate_web_app_data:9
msgid "The parsed init data"
msgstr ""
#: of telebot.util.quick_markup:1
msgid ""
"Returns a reply markup from a dict in this format: {'text': kwargs} This "
"is useful to avoid always typing 'btn1 = InlineKeyboardButton(...)' 'btn2"
" = InlineKeyboardButton(...)'"
msgstr ""
#: of telebot.util.quick_markup:4 telebot.util.user_link:5
msgid "Example:"
msgstr ""
#: of telebot.util.quick_markup:6
msgid "Using quick_markup:"
msgstr ""
#: of telebot.util.quick_markup:31
msgid ""
"a dict containing all buttons to create in this format: {text: kwargs} "
"{str:}"
msgstr ""
#: of telebot.util.quick_markup:34
msgid "number of :class:`telebot.types.InlineKeyboardButton` objects on each row"
msgstr ""
#: of telebot.util.quick_markup:37
msgid "InlineKeyboardMarkup"
msgstr ""
#: of telebot.util.quick_markup:38
msgid ":obj:`types.InlineKeyboardMarkup`"
msgstr ""
#: of telebot.util.smart_split:1
msgid ""
"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."
msgstr ""
#: of telebot.util.smart_split:6 telebot.util.split_string:4
msgid "The text to split"
msgstr ""
#: of telebot.util.smart_split:9
msgid "The number of maximum characters per part the text is split to."
msgstr ""
#: of telebot.util.smart_split:12 telebot.util.split_string:10
msgid "The splitted text as a list of strings."
msgstr ""
#: of telebot.util.smart_split:13 telebot.util.split_string:11
msgid ":obj:`list` of :obj:`str`"
msgstr ""
#: of telebot.util.split_string:1
msgid ""
"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."
msgstr ""
#: of telebot.util.split_string:7
msgid "The number of characters per line the text is split into."
msgstr ""
#: ../../docstring of telebot.util.update_types:1
msgid "All update types, should be used for allowed_updates parameter in polling."
msgstr ""
#: of telebot.util.user_link:1
msgid ""
"Returns an HTML user link. This is useful for reports. Attention: Don't "
"forget to set parse_mode to 'HTML'!"
msgstr ""
#: of telebot.util.user_link:11
msgid ""
"You can use formatting.* for all other formatting options(bold, italic, "
"links, and etc.) This method is kept for backward compatibility, and it "
"is recommended to use formatting.* for more options."
msgstr ""
#: of telebot.util.user_link:15
msgid "the user (not the user_id)"
msgstr ""
#: of telebot.util.user_link:18
msgid "include the user_id"
msgstr ""
#: of telebot.util.user_link:21
msgid "HTML user link"
msgstr ""
#: of telebot.util.validate_web_app_data:1
msgid "Validates web app data."
msgstr ""
#: of telebot.util.webhook_google_functions:1
msgid "A webhook endpoint for Google Cloud Functions FaaS."
msgstr ""
#: of telebot.util.webhook_google_functions:3
msgid "The bot instance"
msgstr ""
#: of telebot.util.webhook_google_functions:6
msgid "The request object"
msgstr ""
#: of telebot.util.webhook_google_functions:9
msgid "The response object"
msgstr ""
#~ msgid "int row width"
#~ msgstr ""

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,130 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../calldata.rst:4
msgid "Callback data factory"
msgstr "Фабрика callback data"
#: ../../calldata.rst:6
msgid "Callback data factory in pyTelegramBotAPI"
msgstr "Фабрика callback data в pyTelegramBotAPI"
#: ../../calldata.rst:6
msgid ""
"ptba, pytba, pyTelegramBotAPI, callbackdatafactory, guide, callbackdata, "
"factory"
msgstr ""
"ptba, pytba, pyTelegramBotAPI, callbackdatafactory, гайд, callbackdata, "
"фабрика"
#: ../../calldata.rst:12
msgid "callback\\_data file"
msgstr "Файл callback\\_data"
#: of telebot.callback_data:1
msgid "Callback data factory's file."
msgstr "Файл фабрики callback data."
#: of telebot.callback_data.CallbackData:1
#: telebot.callback_data.CallbackDataFilter:1
msgid "Bases: :py:class:`object`"
msgstr "Базовые классы: :py:class:`object`"
#: of telebot.callback_data.CallbackData:1
msgid "Callback data factory This class will help you to work with CallbackQuery"
msgstr "Фабрика Callback data. Этот класс поможет вам в работе с CallbackQuery"
#: of telebot.callback_data.CallbackData.filter:1
msgid "Generate filter"
msgstr "Сгенерировать фильтр"
#: of telebot.callback_data.CallbackData.filter
#: telebot.callback_data.CallbackData.new
#: telebot.callback_data.CallbackData.parse
#: telebot.callback_data.CallbackDataFilter.check
msgid "Parameters"
msgstr ""
#: of telebot.callback_data.CallbackData.filter:3
msgid "specified named parameters will be checked with CallbackQuery.data"
msgstr "заданные именованные параметры будут проверены в CallbackQuery.data"
#: of telebot.callback_data.CallbackData.filter
#: telebot.callback_data.CallbackData.new
#: telebot.callback_data.CallbackData.parse
#: telebot.callback_data.CallbackDataFilter.check
msgid "Returns"
msgstr ""
#: of telebot.callback_data.CallbackData.filter:4
msgid "CallbackDataFilter class"
msgstr "Класс CallbackDataFilter"
#: of telebot.callback_data.CallbackData.new:1
msgid "Generate callback data"
msgstr "Сгенерировать callback data"
#: of telebot.callback_data.CallbackData.new:3
msgid "positional parameters of CallbackData instance parts"
msgstr "позиционные параметры экземпляра CallbackData"
#: of telebot.callback_data.CallbackData.new:4
msgid "named parameters"
msgstr "именованные параметры"
#: of telebot.callback_data.CallbackData.new:5
msgid "str"
msgstr ""
#: of telebot.callback_data.CallbackData.parse:1
msgid "Parse data from the callback data"
msgstr "Получить данные из callback data"
#: of telebot.callback_data.CallbackData.parse:3
msgid ""
"string, use to telebot.types.CallbackQuery to parse it from string to a "
"dict"
msgstr ""
"string, примените к telebot.types.CallbackQuery, чтобы преобразовать "
"callback_data из строки (str) в словарь (dict)"
#: of telebot.callback_data.CallbackData.parse:4
msgid "dict parsed from callback data"
msgstr "словарь (dict), полученный из callback data"
#: of telebot.callback_data.CallbackDataFilter:1
msgid "Filter for CallbackData."
msgstr "Фильтр для CallbackData."
#: of telebot.callback_data.CallbackDataFilter.check:1
msgid "Checks if query.data appropriates to specified config"
msgstr "Проверяет, соответствует ли query.data заданной конфигурации"
#: of telebot.callback_data.CallbackDataFilter.check:3
msgid "telebot.types.CallbackQuery"
msgstr ""
#: of telebot.callback_data.CallbackDataFilter.check:6
msgid "True if query.data appropriates to specified config"
msgstr "True, если query.data соответствует заданной конфигурации"
#: of telebot.callback_data.CallbackDataFilter.check
msgid "Return type"
msgstr ""

View File

@ -0,0 +1,251 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../formatting.rst:3
msgid "Formatting options"
msgstr "Параметры форматирования"
#: ../../formatting.rst:5
msgid "Formatting options in pyTelegramBotAPI"
msgstr "Параметры форматирования в pyTelegramBotAPI"
#: ../../formatting.rst:5
msgid "html, markdown, parse_mode, formatting, ptba, pytba, pyTelegramBotAPI"
msgstr "html, markdown, parse_mode, форматирование, ptba, pytba, pyTelegramBotAPI"
#: of telebot.formatting:1
msgid "Markdown & HTML formatting functions."
msgstr "Функции форматирования Markdown & HTML."
#: of telebot.formatting.escape_html:1
msgid "Escapes HTML characters in a string of HTML."
msgstr "Пропускает HTML символы в HTML строке."
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
#: telebot.formatting.format_text telebot.formatting.hbold
#: telebot.formatting.hcode telebot.formatting.hide_link
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
#: telebot.formatting.hunderline telebot.formatting.mbold
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
#: telebot.formatting.munderline
msgid "Parameters"
msgstr ""
#: of telebot.formatting.escape_html:3
msgid "The string of HTML to escape."
msgstr "HTML строка, которую нужно пропустить."
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
#: telebot.formatting.format_text telebot.formatting.hbold
#: telebot.formatting.hcode telebot.formatting.hide_link
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
#: telebot.formatting.hunderline telebot.formatting.mbold
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
#: telebot.formatting.munderline
msgid "Returns"
msgstr ""
#: of telebot.formatting.escape_html:6 telebot.formatting.escape_markdown:8
msgid "The escaped string."
msgstr "Пропускаемая строка."
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
#: telebot.formatting.format_text telebot.formatting.hbold
#: telebot.formatting.hcode telebot.formatting.hide_link
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
#: telebot.formatting.hunderline telebot.formatting.mbold
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
#: telebot.formatting.munderline
msgid "Return type"
msgstr ""
#: of telebot.formatting.escape_html:7 telebot.formatting.escape_markdown:9
#: telebot.formatting.format_text:17 telebot.formatting.hbold:10
#: telebot.formatting.hcode:10 telebot.formatting.hide_link:7
#: telebot.formatting.hitalic:10 telebot.formatting.hlink:13
#: telebot.formatting.hpre:10 telebot.formatting.hspoiler:10
#: telebot.formatting.hstrikethrough:10 telebot.formatting.hunderline:10
#: telebot.formatting.mbold:10 telebot.formatting.mcode:10
#: telebot.formatting.mitalic:10 telebot.formatting.mlink:13
#: telebot.formatting.mspoiler:10 telebot.formatting.mstrikethrough:10
#: telebot.formatting.munderline:10
msgid ":obj:`str`"
msgstr ""
#: of telebot.formatting.escape_markdown:1
msgid "Escapes Markdown characters in a string of Markdown."
msgstr "Пропускает Markdown символы в Markdown строке."
#: of telebot.formatting.escape_markdown:3
msgid "Credits to: simonsmh"
msgstr ""
#: of telebot.formatting.escape_markdown:5
msgid "The string of Markdown to escape."
msgstr "Markdown строка, которую нужно пропустить."
#: of telebot.formatting.format_text:1
msgid "Formats a list of strings into a single string."
msgstr "Преобразовывает набор строк в одну."
#: of telebot.formatting.format_text:10
msgid "Strings to format."
msgstr "Строки для преобразования."
#: of telebot.formatting.format_text:13
msgid "The separator to use between each string."
msgstr "Символ для разделения строк."
#: of telebot.formatting.format_text:16 telebot.formatting.hbold:9
#: telebot.formatting.hcode:9 telebot.formatting.hitalic:9
#: telebot.formatting.hlink:12 telebot.formatting.hpre:9
#: telebot.formatting.hspoiler:9 telebot.formatting.hstrikethrough:9
#: telebot.formatting.hunderline:9 telebot.formatting.mbold:9
#: telebot.formatting.mcode:9 telebot.formatting.mitalic:9
#: telebot.formatting.mlink:12 telebot.formatting.mspoiler:9
#: telebot.formatting.mstrikethrough:9 telebot.formatting.munderline:9
msgid "The formatted string."
msgstr "Преобразованная строка."
#: of telebot.formatting.hbold:1
msgid "Returns an HTML-formatted bold string."
msgstr "Возвращает выделенную жирным шрифтом HTML строку."
#: of telebot.formatting.hbold:3 telebot.formatting.mbold:3
msgid "The string to bold."
msgstr "Строка для выделения жирным шрифтом."
#: of telebot.formatting.hbold:6 telebot.formatting.hcode:6
#: telebot.formatting.hitalic:6 telebot.formatting.hlink:9
#: telebot.formatting.hpre:6 telebot.formatting.hspoiler:6
#: telebot.formatting.hstrikethrough:6 telebot.formatting.hunderline:6
#: telebot.formatting.mbold:6 telebot.formatting.mcode:6
#: telebot.formatting.mitalic:6 telebot.formatting.mlink:9
#: telebot.formatting.mspoiler:6 telebot.formatting.mstrikethrough:6
#: telebot.formatting.munderline:6
msgid "True if you need to escape special characters. Defaults to True."
msgstr "True если вам нужно пропустить спец. символы. По умолчанию True."
#: of telebot.formatting.hcode:1
msgid "Returns an HTML-formatted code string."
msgstr "Возвращает выделенную как код HTML строку."
#: of telebot.formatting.hcode:3 telebot.formatting.mcode:3
msgid "The string to code."
msgstr "Строка для выделения как код."
#: of telebot.formatting.hide_link:1
msgid "Hide url of an image."
msgstr "Делает невидимым URL изображения."
#: of telebot.formatting.hide_link:3
msgid "The url of the image."
msgstr "URL изображения."
#: of telebot.formatting.hide_link:6
msgid "The hidden url."
msgstr "Невидимый URL."
#: of telebot.formatting.hitalic:1
msgid "Returns an HTML-formatted italic string."
msgstr "Возвращает выделенную курсивом HTML строку."
#: of telebot.formatting.hitalic:3 telebot.formatting.mitalic:3
msgid "The string to italicize."
msgstr "Строка для выделения курсивом."
#: of telebot.formatting.hlink:1
msgid "Returns an HTML-formatted link string."
msgstr "Возвращает HTML строку с гиперссылкой."
#: of telebot.formatting.hlink:3 telebot.formatting.mlink:3
msgid "The string to link."
msgstr "Строка для добавления гиперссылки."
#: of telebot.formatting.hlink:6 telebot.formatting.mlink:6
msgid "The URL to link to."
msgstr "URL для создания гиперссылки."
#: of telebot.formatting.hpre:1
msgid "Returns an HTML-formatted preformatted string."
msgstr "Возвращает предварительно отформатированную HTML строку."
#: of telebot.formatting.hpre:3
msgid "The string to preformatted."
msgstr "Строка для предварительного форматирования."
#: of telebot.formatting.hspoiler:1
msgid "Returns an HTML-formatted spoiler string."
msgstr "Возвращает выделенную как спойлер HTML строку."
#: of telebot.formatting.hspoiler:3 telebot.formatting.mspoiler:3
msgid "The string to spoiler."
msgstr "Строка для выделения как спойлер."
#: of telebot.formatting.hstrikethrough:1
msgid "Returns an HTML-formatted strikethrough string."
msgstr "Возвращает зачеркнутую HTML строку."
#: of telebot.formatting.hstrikethrough:3 telebot.formatting.mstrikethrough:3
msgid "The string to strikethrough."
msgstr "Строка для зачеркивания."
#: of telebot.formatting.hunderline:1
msgid "Returns an HTML-formatted underline string."
msgstr "Возвращает подчеркнутую HTML строку."
#: of telebot.formatting.hunderline:3 telebot.formatting.munderline:3
msgid "The string to underline."
msgstr "Строка для подчёркивания."
#: of telebot.formatting.mbold:1
msgid "Returns a Markdown-formatted bold string."
msgstr "Возвращает выделенную жирным шрифтом Markdown строку."
#: of telebot.formatting.mcode:1
msgid "Returns a Markdown-formatted code string."
msgstr "Возвращает выделенную как код Markdown строку."
#: of telebot.formatting.mitalic:1
msgid "Returns a Markdown-formatted italic string."
msgstr "Возвращает выделенную курсивом Markdown строку."
#: of telebot.formatting.mlink:1
msgid "Returns a Markdown-formatted link string."
msgstr "Возвращает Markdown строку с гиперссылкой."
#: of telebot.formatting.mspoiler:1
msgid "Returns a Markdown-formatted spoiler string."
msgstr "Возвращает выделенную как спойлер Markdown строку."
#: of telebot.formatting.mstrikethrough:1
msgid "Returns a Markdown-formatted strikethrough string."
msgstr "Возвращает зачеркнутую Markdown строку."
#: of telebot.formatting.munderline:1
msgid "Returns a Markdown-formatted underline string."
msgstr "Возвращает подчеркнутую Markdown строку."

View File

@ -0,0 +1,128 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../index.rst:8
msgid "Welcome to pyTelegramBotAPI's documentation!"
msgstr "Добро пожаловать в документацию pyTelegramBotAPI!"
#: ../../index.rst:10
msgid "Official documentation of pyTelegramBotAPI"
msgstr "Официальная документация pyTelegramBotAPI"
#: ../../index.rst:10
msgid "ptba, pytba, pyTelegramBotAPI, documentation, guide"
msgstr "ptba, pytba, pyTelegramBotAPI, документация, гайд"
#: ../../index.rst:17
msgid "TeleBot"
msgstr ""
#: ../../index.rst:18
msgid ""
"TeleBot is synchronous and asynchronous implementation of `Telegram Bot "
"API <https://core.telegram.org/bots/api>`_."
msgstr ""
"TeleBot это синхронная и асинхронная реализация `Telegram Bot "
"API <https://core.telegram.org/bots/api>`_."
#: ../../index.rst:21
msgid "Chats"
msgstr "Чаты"
#: ../../index.rst:22
msgid ""
"English chat: `Private chat "
"<https://telegram.me/joinchat/Bn4ixj84FIZVkwhk2jag6A>`__"
msgstr ""
"Англоязычный чат: `Private chat "
"<https://telegram.me/joinchat/Bn4ixj84FIZVkwhk2jag6A>`__"
#: ../../index.rst:24
msgid ""
"Russian chat: `@pytelegrambotapi_talks_ru "
"<https://t.me/pytelegrambotapi_talks_ru>`__"
msgstr ""
"Русскоязычный чат: `@pytelegrambotapi_talks_ru "
"<https://t.me/pytelegrambotapi_talks_ru>`__"
#: ../../index.rst:26
msgid "News: `@pyTelegramBotAPI <https://t.me/pytelegrambotapi>`__"
msgstr "Новости: `@pyTelegramBotAPI <https://t.me/pytelegrambotapi>`__"
#: ../../index.rst:28
msgid "Pypi: `Pypi <https://pypi.org/project/pyTelegramBotAPI/>`__"
msgstr ""
#: ../../index.rst:30
msgid ""
"Source: `Github repository "
"<https://github.com/eternnoir/pyTelegramBotAPI>`__"
msgstr ""
"Исходники: `Github repository "
"<https://github.com/eternnoir/pyTelegramBotAPI>`__"
#: ../../index.rst:33
msgid "Some features:"
msgstr "Некоторые особенности:"
#: ../../index.rst:34
msgid "Easy to learn and use."
msgstr "Простой в изучении и использовании."
#: ../../index.rst:36
msgid "Easy to understand."
msgstr "Простой в понимании."
#: ../../index.rst:38
msgid "Both sync and async."
msgstr "И синхронный, и асинхронный."
#: ../../index.rst:40
msgid "Examples on features."
msgstr "Примеры возможностей."
#: ../../index.rst:42
msgid "States"
msgstr "Состояния (стейты, FSM)"
#: ../../index.rst:44
msgid "And more..."
msgstr "И другое..."
#: ../../index.rst:47
msgid "Content"
msgstr "Содержимое"
#: ../../index.rst:63
msgid "Indices and tables"
msgstr "Ссылки"
#: ../../index.rst:65
msgid ":ref:`genindex`"
msgstr ""
#: ../../index.rst:66
msgid ":ref:`modindex`"
msgstr ""
#: ../../index.rst:67
msgid ":ref:`search`"
msgstr ""

View File

@ -0,0 +1,59 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../install.rst:3
msgid "Installation Guide"
msgstr "Гайд по установке"
#: ../../install.rst:5
msgid "Installation of pyTelegramBotAPI"
msgstr "Установка pyTelegramBotAPI"
#: ../../install.rst:5
msgid "ptba, pytba, pyTelegramBotAPI, installation, guide"
msgstr "ptba, pytba, pyTelegramBotAPI, установка, гайд"
#: ../../install.rst:11
msgid "Using PIP"
msgstr "Используя PIP"
#: ../../install.rst:17
msgid "Using pipenv"
msgstr "Используя pipenv"
#: ../../install.rst:23
msgid "By cloning repository"
msgstr "Клонируя репозиторий"
#: ../../install.rst:31
msgid "Directly using pip"
msgstr "Напрямую используя pip"
#: ../../install.rst:37
msgid "It is generally recommended to use the first option."
msgstr "Рекомендуется использовать первый вариант."
#: ../../install.rst:39
msgid ""
"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:"
msgstr "Новые версии библиотеки имеют больше фич, улучшений и баг фиксов. Не забывайте"
" обновляться вызывая:"

View File

@ -0,0 +1,40 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../quick_start.rst:4
msgid "Quick start"
msgstr "Быстрый старт"
#: ../../quick_start.rst:6
msgid "Quickstart guide"
msgstr "Быстрый старт - гайд"
#: ../../quick_start.rst:6
msgid "ptba, pytba, pyTelegramBotAPI, quickstart, guide"
msgstr "ptba, pytba, pyTelegramBotAPI, быстрый старт, гайд"
#: ../../quick_start.rst:11
msgid "Synchronous TeleBot"
msgstr "Синхронный телебот"
#: ../../quick_start.rst:16
msgid "Asynchronous TeleBot"
msgstr "Асинхронный телебот"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,393 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-08 23:07+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../source/util.rst:3
msgid "Utils"
msgstr "Утилиты"
#: ../../source/util.rst:5
msgid "Utils in pyTelegramBotAPI"
msgstr "Утилиты в pyTelegramBotAPI"
#: ../../source/util.rst:5
msgid "ptba, pytba, pyTelegramBotAPI, utils, guide"
msgstr "ptba, pytba, pyTelegramBotAPI, утилиты, гайд"
#: ../../source/util.rst:11
msgid "util file"
msgstr "Файл util"
#: of telebot.util.antiflood:1
msgid ""
"Use this function inside loops in order to avoid getting TooManyRequests "
"error. Example:"
msgstr ""
"Используйте эту функцию в циклах, чтобы избежать ошибки TooManyRequests. "
"Пример:"
#: of telebot.service_utils.is_bytes telebot.service_utils.is_dict
#: telebot.service_utils.is_pil_image telebot.util.antiflood
#: telebot.util.escape telebot.util.extract_arguments
#: telebot.util.extract_command telebot.util.is_command
#: telebot.util.parse_web_app_data telebot.util.quick_markup
#: telebot.util.smart_split telebot.util.split_string telebot.util.user_link
#: telebot.util.validate_web_app_data telebot.util.webhook_google_functions
msgid "Parameters"
msgstr ""
#: of telebot.util.antiflood:10
msgid "The function to call"
msgstr "Вызываемая функция"
#: of telebot.util.antiflood:13
msgid "Number of retries to send"
msgstr ""
#: of telebot.util.antiflood:16
msgid "The arguments to pass to the function"
msgstr "Аргументы, для передачи в функцию"
#: of telebot.util.antiflood:19
msgid "The keyword arguments to pass to the function"
msgstr "Именованные аргументы для передачи в функцию"
#: of telebot.service_utils.generate_random_token
#: telebot.service_utils.is_bytes telebot.service_utils.is_dict
#: telebot.service_utils.is_pil_image telebot.util.antiflood
#: telebot.util.escape telebot.util.extract_arguments
#: telebot.util.extract_command telebot.util.is_command
#: telebot.util.parse_web_app_data telebot.util.quick_markup
#: telebot.util.smart_split telebot.util.split_string telebot.util.user_link
#: telebot.util.validate_web_app_data telebot.util.webhook_google_functions
msgid "Returns"
msgstr ""
#: of telebot.util.antiflood:22
msgid "None"
msgstr ""
#: of telebot.service_utils.chunks:1
msgid "Yield successive n-sized chunks from lst."
msgstr "Генерирует последовательные части списка, состоящие из n элементов."
#: ../../docstring of telebot.util.content_type_media:1
msgid "Contains all media content types."
msgstr "Содержит все виды медиа."
#: ../../docstring of telebot.util.content_type_service:1
msgid "Contains all service content types such as `User joined the group`."
msgstr "Содержит все виды сервисных сообщений, такие как `User joined the group`."
#: of telebot.util.escape:1
msgid ""
"Replaces the following chars in `text` ('&' with '&amp;', '<' with '&lt;'"
" and '>' with '&gt;')."
msgstr ""
"Заменяет следующие символы в `text` ('&' на '&amp;', '<' на '&lt;' и '>' "
"на '&gt;')."
#: of telebot.util.escape:3
msgid "the text to escape"
msgstr "Текст для замены символов"
#: of telebot.util.escape:4
msgid "the escaped text"
msgstr "Отформатированный текст"
#: of telebot.util.extract_arguments:1
msgid "Returns the argument after the command."
msgstr "Возвращает аргументы команды."
#: of telebot.util.extract_arguments:3 telebot.util.extract_command:4
msgid "Examples:"
msgstr "Примеры:"
#: of telebot.util.extract_arguments:10
msgid "String to extract the arguments from a command"
msgstr "Строка для извлечения аргументов команды"
#: of telebot.util.extract_arguments:13
msgid "the arguments if `text` is a command (according to is_command), else None."
msgstr ""
"Аргументы, если `text` является командой (согласно is_command), в "
"остальных случаях None."
#: of telebot.service_utils.generate_random_token
#: telebot.service_utils.is_bytes telebot.service_utils.is_dict
#: telebot.service_utils.is_pil_image telebot.util.extract_arguments
#: telebot.util.extract_command telebot.util.is_command
#: telebot.util.quick_markup telebot.util.smart_split telebot.util.split_string
#: telebot.util.user_link
msgid "Return type"
msgstr ""
#: of telebot.util.extract_arguments:14 telebot.util.extract_command:16
msgid ":obj:`str` or :obj:`None`"
msgstr ":obj:`str` или :obj:`None`"
#: of telebot.util.extract_command:1
msgid ""
"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."
msgstr ""
"Извлекает команду из `text` (исключает '/') если `text` является командой"
" (см. is_command). Если `text` не является командой, эта функция "
"возвращает None."
#: of telebot.util.extract_command:12
msgid "String to extract the command from"
msgstr "Строка, из которой нужно извлечь команду"
#: of telebot.util.extract_command:15
msgid "the command if `text` is a command (according to is_command), else None."
msgstr ""
"Команда, если `text` является командой (согласно is_command), в остальных"
" случаях None."
#: of telebot.service_utils.generate_random_token:1
msgid ""
"Generates a random token consisting of letters and digits, 16 characters "
"long."
msgstr ""
"Генерирует рандомный токен, состоящий из латинских букв и цифр длиной 16 "
"символов."
#: of telebot.service_utils.generate_random_token:3
msgid "a random token"
msgstr "Сгенерированный токен"
#: of telebot.service_utils.generate_random_token:4 telebot.util.user_link:22
msgid ":obj:`str`"
msgstr ""
#: of telebot.service_utils.is_bytes:1
msgid "Returns True if the given object is a bytes object."
msgstr "Возвращает True если полученный объект является bytes."
#: of telebot.service_utils.is_bytes:3 telebot.service_utils.is_dict:3
#: telebot.service_utils.is_pil_image:3
msgid "object to be checked"
msgstr "Объект для проверки"
#: of telebot.service_utils.is_bytes:6
msgid "True if the given object is a bytes object."
msgstr "True, если полученный объект является bytes."
#: of telebot.service_utils.is_bytes:7 telebot.service_utils.is_dict:7
#: telebot.service_utils.is_pil_image:7 telebot.util.is_command:7
msgid ":obj:`bool`"
msgstr ""
#: of telebot.util.is_command:1
msgid ""
"Checks if `text` is a command. Telegram chat commands start with the '/' "
"character."
msgstr ""
"Проверяет, является ли `text` командой. Команды в Telegram начинаются с "
"символа '/'."
#: of telebot.util.is_command:3
msgid "Text to check."
msgstr "Текст для проверки."
#: of telebot.util.is_command:6
msgid "True if `text` is a command, else False."
msgstr "True, если `text` является командой, иначе False."
#: of telebot.service_utils.is_dict:1
msgid "Returns True if the given object is a dictionary."
msgstr "Возвращает True, если полученный объект является словарём (dict)."
#: of telebot.service_utils.is_dict:6
msgid "True if the given object is a dictionary."
msgstr "True, если полученный объект является словарём (dict)."
#: of telebot.service_utils.is_pil_image:1
msgid "Returns True if the given object is a PIL.Image.Image object."
msgstr "Возвращает True, если полученный объект является PIL.Image.Image."
#: of telebot.service_utils.is_pil_image:6
msgid "True if the given object is a PIL.Image.Image object."
msgstr "True, если полученный объект является PIL.Image.Image."
#: of telebot.service_utils.is_string:1
msgid "Returns True if the given object is a string."
msgstr "Возвращает True, если полученный объект является строкой (str)."
#: of telebot.util.parse_web_app_data:1
msgid "Parses web app data."
msgstr "Обрабатывает данные, полученные от web app."
#: of telebot.util.parse_web_app_data:3 telebot.util.validate_web_app_data:3
msgid "The bot token"
msgstr "Токен бота"
#: of telebot.util.parse_web_app_data:6 telebot.util.validate_web_app_data:6
msgid "The raw init data"
msgstr "Необработанные данные"
#: of telebot.util.parse_web_app_data:9 telebot.util.validate_web_app_data:9
msgid "The parsed init data"
msgstr "Обработанные данные"
#: of telebot.util.quick_markup:1
msgid ""
"Returns a reply markup from a dict in this format: {'text': kwargs} This "
"is useful to avoid always typing 'btn1 = InlineKeyboardButton(...)' 'btn2"
" = InlineKeyboardButton(...)'"
msgstr ""
"Возвращает reply markup из словаря следующего формата: {'text': kwargs}. "
"Удобно использовать вместо постоянного использования 'btn1 = "
"InlineKeyboardButton(...)' 'btn2 = InlineKeyboardButton(...)'"
#: of telebot.util.quick_markup:4 telebot.util.user_link:5
msgid "Example:"
msgstr "Пример:"
#: of telebot.util.quick_markup:6
msgid "Using quick_markup:"
msgstr "Используя quick_markup:"
#: of telebot.util.quick_markup:31
msgid ""
"a dict containing all buttons to create in this format: {text: kwargs} "
"{str:}"
msgstr ""
"Словарь, содержащий все кнопки для создания reply markup в следующем "
"формате: {text: kwargs} {str:}"
#: of telebot.util.quick_markup:34
msgid "number of :class:`telebot.types.InlineKeyboardButton` objects on each row"
msgstr ""
#: of telebot.util.quick_markup:37
msgid "InlineKeyboardMarkup"
msgstr ""
#: of telebot.util.quick_markup:38
msgid ":obj:`types.InlineKeyboardMarkup`"
msgstr ""
#: of telebot.util.smart_split:1
msgid ""
"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."
msgstr ""
"Разбивает строку на несколько, каждая из которых будет не длиннее "
"`characters_per_string`. Удобно использовать для разбиения одного "
"гигантского сообщения на несколько. Если `chars_per_string` > 4096: "
"`chars_per_string` = 4096. Разбивает строку по '\\n', '. ' или ' ' именно"
" в таком порядке."
#: of telebot.util.smart_split:6 telebot.util.split_string:4
msgid "The text to split"
msgstr "Текст для разбиения"
#: of telebot.util.smart_split:9
msgid "The number of maximum characters per part the text is split to."
msgstr ""
"Максимальное количество символов в части текста, на которые он будет "
"разбит."
#: of telebot.util.smart_split:12 telebot.util.split_string:10
msgid "The splitted text as a list of strings."
msgstr "Список частей разбитого текста."
#: of telebot.util.smart_split:13 telebot.util.split_string:11
msgid ":obj:`list` of :obj:`str`"
msgstr ""
#: of telebot.util.split_string:1
msgid ""
"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."
msgstr ""
"Разбивает одну строку на несколько, каждая из которых будет не длиннее "
"`characters_per_string`. Удобно использовать для разбиения одного "
"гигантского сообщения на несколько."
#: of telebot.util.split_string:7
msgid "The number of characters per line the text is split into."
msgstr "Количество символов в одной строке, на которые будет разбит текст."
#: ../../docstring of telebot.util.update_types:1
msgid "All update types, should be used for allowed_updates parameter in polling."
msgstr ""
"Все виды апдейтов, рекомендуется использовать в качестве параметра "
"allowed_updates функции polling."
#: of telebot.util.user_link:1
msgid ""
"Returns an HTML user link. This is useful for reports. Attention: Don't "
"forget to set parse_mode to 'HTML'!"
msgstr ""
"Возвращает HTML ссылку на пользователя. Удобно использовать для отчетов. "
"Важно: Не забудьте установить значение 'HTML' в parse_mode!"
#: of telebot.util.user_link:11
msgid ""
"You can use formatting.* for all other formatting options(bold, italic, "
"links, and etc.) This method is kept for backward compatibility, and it "
"is recommended to use formatting.* for more options."
msgstr ""
"Вы можете использовать formatting.* во всех остальных вариантах "
"форматирования(bold, italic, links, и прочее). Этот метод сохранён для "
"обратной совместимости, рекомендуется использовать formatting.* для "
"большего количества вариантов."
#: of telebot.util.user_link:15
msgid "the user (not the user_id)"
msgstr "Пользователь (не id пользователя)"
#: of telebot.util.user_link:18
msgid "include the user_id"
msgstr "Добавить id пользователя"
#: of telebot.util.user_link:21
msgid "HTML user link"
msgstr "Ссылка на пользователя в формате HTML"
#: of telebot.util.validate_web_app_data:1
msgid "Validates web app data."
msgstr "Проверяет данные, полученные от web app."
#: of telebot.util.webhook_google_functions:1
msgid "A webhook endpoint for Google Cloud Functions FaaS."
msgstr "Endpoint вебхука для Google Cloud Functions FaaS."
#: of telebot.util.webhook_google_functions:3
msgid "The bot instance"
msgstr "Инстанс бота"
#: of telebot.util.webhook_google_functions:6
msgid "The request object"
msgstr "HTTP-запрос"
#: of telebot.util.webhook_google_functions:9
msgid "The response object"
msgstr "Объект, полученный в качестве ответа"
#~ msgid "int row width"
#~ msgstr "Количество кнопок в одной строке, int"

View File

@ -0,0 +1,27 @@
from telebot.async_telebot import AsyncTeleBot
from telebot.asyncio_handler_backends import ContinueHandling
bot = AsyncTeleBot('TOKEN')
@bot.message_handler(commands=['start'])
async def start(message):
await bot.send_message(message.chat.id, 'Hello World!')
return ContinueHandling()
@bot.message_handler(commands=['start'])
async def start2(message):
"""
This handler comes after the first one, but it will never be called.
But you can call it by returning ContinueHandling() in the first handler.
If you return ContinueHandling() in the first handler, the next
registered handler with appropriate filters will be called.
"""
await bot.send_message(message.chat.id, 'Hello World2!')
import asyncio
asyncio.run(bot.polling()) # just a reminder that infinity polling
# wraps polling into try/except block just as sync version,
# but you can use any of them because neither of them stops if you
# pass non_stop=True

View File

@ -0,0 +1,28 @@
#!/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)
import asyncio
# only for versions 4.7.0+
asyncio.run(bot.polling(restart_on_change=True))

View File

@ -0,0 +1,89 @@
#!/usr/bin/env python
"""
Asynchronous Telegram Echo Bot example.
This is a simple bot that echoes each message that is received onto the chat.
It uses the Starlette ASGI framework to receive updates via webhook requests.
"""
import uvicorn
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import PlainTextResponse, Response
from starlette.routing import Route
from telebot.async_telebot import AsyncTeleBot
from telebot.types import Message, Update
API_TOKEN = "TOKEN"
WEBHOOK_HOST = "<ip/domain>"
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
WEBHOOK_LISTEN = "0.0.0.0"
WEBHOOK_SSL_CERT = "./webhook_cert.pem" # Path to the ssl certificate
WEBHOOK_SSL_PRIV = "./webhook_pkey.pem" # Path to the ssl private key
WEBHOOK_URL = f"https://{WEBHOOK_HOST}:{WEBHOOK_PORT}/telegram"
WEBHOOK_SECRET_TOKEN = "SECRET_TOKEN"
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
bot = AsyncTeleBot(token=API_TOKEN)
# BOT HANDLERS
@bot.message_handler(commands=["help", "start"])
async def send_welcome(message: Message):
"""
Handle '/start' and '/help'
"""
await bot.reply_to(
message,
("Hi there, I am EchoBot.\n" "I am here to echo your kind words back to you."),
)
@bot.message_handler(func=lambda _: True, content_types=["text"])
async def echo_message(message: Message):
"""
Handle all other messages
"""
await bot.reply_to(message, message.text)
# WEBSERVER HANDLERS
async def telegram(request: Request) -> Response:
"""Handle incoming Telegram updates."""
token_header_name = "X-Telegram-Bot-Api-Secret-Token"
if request.headers.get(token_header_name) != WEBHOOK_SECRET_TOKEN:
return PlainTextResponse("Forbidden", status_code=403)
await bot.process_new_updates([Update.de_json(await request.json())])
return Response()
async def startup() -> None:
"""Register webhook for telegram updates."""
webhook_info = await bot.get_webhook_info(30)
if WEBHOOK_URL != webhook_info.url:
logger.debug(
f"updating webhook url, old: {webhook_info.url}, new: {WEBHOOK_URL}"
)
if not await bot.set_webhook(
url=WEBHOOK_URL, secret_token=WEBHOOK_SECRET_TOKEN
):
raise RuntimeError("unable to set webhook")
app = Starlette(
routes=[
Route("/telegram", telegram, methods=["POST"]),
],
on_startup=[startup],
)
uvicorn.run(
app,
host=WEBHOOK_HOST,
port=WEBHOOK_LISTEN,
ssl_certfile=WEBHOOK_SSL_CERT,
ssl_keyfile=WEBHOOK_SSL_PRIV,
)

View File

@ -0,0 +1,23 @@
from telebot import TeleBot
from telebot.handler_backends import ContinueHandling
bot = TeleBot('TOKEN')
@bot.message_handler(commands=['start'])
def start(message):
bot.send_message(message.chat.id, 'Hello World!')
return ContinueHandling()
@bot.message_handler(commands=['start'])
def start2(message):
"""
This handler comes after the first one, but it will never be called.
But you can call it by returning ContinueHandling() in the first handler.
If you return ContinueHandling() in the first handler, the next
registered handler with appropriate filters will be called.
"""
bot.send_message(message.chat.id, 'Hello World2!')
bot.infinity_polling()

View File

@ -0,0 +1,28 @@
#!/usr/bin/python
# This is a simple echo bot using the decorator mechanism.
# It echoes any incoming text messages.
import telebot
API_TOKEN = '<api_token>'
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.
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)
def echo_message(message):
bot.reply_to(message, message.text)
# only for versions 4.7.0+
bot.infinity_polling(restart_on_change=True)

View File

@ -42,7 +42,7 @@ def query_video(inline_query):
try:
r = types.InlineQueryResultVideo('1',
'https://github.com/eternnoir/pyTelegramBotAPI/blob/master/tests/test_data/test_video.mp4?raw=true',
'video/mp4', 'Video',
'video/mp4',
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/rooster.jpg',
'Title'
)

32
examples/poll_example.py Normal file
View File

@ -0,0 +1,32 @@
#!/usr/bin/python
# This is an example file to create quiz polls
import telebot
API_TOKEN = "<api_token>"
bot = telebot.TeleBot(API_TOKEN)
@bot.message_handler(commands=["poll"])
def create_poll(message):
bot.send_message(message.chat.id, "English Article Test")
answer_options = ["a", "an", "the", "-"]
bot.send_poll(
chat_id=message.chat.id,
question="We are going to '' park.",
options=answer_options,
type="quiz",
correct_option_id=2,
is_anonymous=False,
)
@bot.poll_answer_handler()
def handle_poll(poll):
# This handler can be used to log User answers and to send next poll
pass
bot.infinity_polling()

View File

@ -0,0 +1,50 @@
"""
Example of running PyTelegramBotAPI serverless in Amazon AWS Lambdaю
You have to set your lambda's url as telegram webhook manually https://core.telegram.org/bots/api#setwebhook
"""
import logging
import telebot
import json
import os
API_TOKEN = os.environ['TELEGRAM_TOKEN']
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
bot = telebot.TeleBot(API_TOKEN, threaded=False)
def process_event(event):
# Get telegram webhook json from event
request_body_dict = json.loads(event['body'])
# Parse updates from json
update = telebot.types.Update.de_json(request_body_dict)
# Run handlers and etc for updates
bot.process_new_updates([update])
def lambda_handler(event, context):
# Process event from aws and respond
process_event(event)
return {
'statusCode': 200
}
# 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)

View File

@ -1,4 +1,4 @@
pytest
requests==2.20.0
wheel==0.24.0
requests==2.31.0
wheel==0.38.1
aiohttp>=3.8.0,<3.9.0

View File

@ -31,6 +31,9 @@ setup(name='pyTelegramBotAPI',
'aiohttp': 'aiohttp',
'fastapi': 'fastapi',
'uvicorn': 'uvicorn',
'psutil': 'psutil',
'coloredlogs': 'coloredlogs',
'watchdog': 'watchdog'
},
classifiers=[
'Development Status :: 5 - Production/Stable',

File diff suppressed because it is too large Load Diff

View File

@ -111,7 +111,13 @@ def _make_request(token, method_name, method='get', params=None, files=None):
params = params or None # Set params to None if empty
result = None
if RETRY_ON_ERROR and RETRY_ENGINE == 1:
if CUSTOM_REQUEST_SENDER:
# noinspection PyCallingNonCallable
result = CUSTOM_REQUEST_SENDER(
method, request_url, params=params, files=files,
timeout=(connect_timeout, read_timeout), proxies=proxy)
elif RETRY_ON_ERROR and RETRY_ENGINE == 1:
got_result = False
current_try = 0
while not got_result and current_try<MAX_RETRIES-1:
@ -146,11 +152,6 @@ def _make_request(token, method_name, method='get', params=None, files=None):
result = http.request(
method, request_url, params=params, files=files,
timeout=(connect_timeout, read_timeout), proxies=proxy)
elif CUSTOM_REQUEST_SENDER:
# noinspection PyCallingNonCallable
result = CUSTOM_REQUEST_SENDER(
method, request_url, params=params, files=files,
timeout=(connect_timeout, read_timeout), proxies=proxy)
else:
result = _get_req_session().request(
method, request_url, params=params, files=files,
@ -236,23 +237,8 @@ def send_message(
token, chat_id, text,
disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
entities=None, allow_sending_without_reply=None, protect_content=None):
"""
Use this method to send text messages. On success, the sent Message is returned.
:param token:
:param chat_id:
:param text:
:param disable_web_page_preview:
:param reply_to_message_id:
:param reply_markup:
:param parse_mode:
:param disable_notification:
:param timeout:
:param entities:
:param allow_sending_without_reply:
:param protect_content:
:return:
"""
entities=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None):
method_url = r'sendMessage'
payload = {'chat_id': str(chat_id), 'text': text}
if disable_web_page_preview is not None:
@ -273,6 +259,8 @@ def send_message(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload, method='post')
@ -367,15 +355,15 @@ def get_chat_member_count(token, chat_id):
return _make_request(token, method_url, params=payload)
def set_sticker_set_thumb(token, name, user_id, thumb):
method_url = r'setStickerSetThumb'
def set_sticker_set_thumbnail(token, name, user_id, thumbnail):
method_url = r'setStickerSetThumbnail'
payload = {'name': name, 'user_id': user_id}
files = {}
if thumb:
if not isinstance(thumb, str):
files['thumb'] = thumb
if thumbnail:
if not isinstance(thumbnail, str):
files['thumbnail'] = thumbnail
else:
payload['thumb'] = thumb
payload['thumbnail'] = thumbnail
return _make_request(token, method_url, params=payload, files=files or None)
@ -399,7 +387,7 @@ def get_chat_member(token, chat_id, user_id):
def forward_message(
token, chat_id, from_chat_id, message_id,
disable_notification=None, timeout=None, protect_content=None):
disable_notification=None, timeout=None, protect_content=None, message_thread_id=None):
method_url = r'forwardMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if disable_notification is not None:
@ -408,12 +396,14 @@ def forward_message(
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_mode=None, caption_entities=None,
disable_notification=None, reply_to_message_id=None, allow_sending_without_reply=None,
reply_markup=None, timeout=None, protect_content=None):
reply_markup=None, timeout=None, protect_content=None, message_thread_id=None):
method_url = r'copyMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if caption is not None:
@ -434,13 +424,15 @@ def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_m
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
def send_dice(
token, chat_id,
emoji=None, disable_notification=None, reply_to_message_id=None,
reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None):
reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
method_url = r'sendDice'
payload = {'chat_id': chat_id}
if emoji:
@ -457,6 +449,8 @@ def send_dice(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
@ -464,7 +458,8 @@ def send_photo(
token, chat_id, photo,
caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
caption_entities=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None, has_spoiler=None):
method_url = r'sendPhoto'
payload = {'chat_id': chat_id}
files = None
@ -492,13 +487,17 @@ def send_photo(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
if has_spoiler is not None:
payload['has_spoiler'] = has_spoiler
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_media_group(
token, chat_id, media,
disable_notification=None, reply_to_message_id=None,
timeout=None, allow_sending_without_reply=None, protect_content=None):
timeout=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
method_url = r'sendMediaGroup'
media_json, files = convert_input_media_array(media)
payload = {'chat_id': chat_id, 'media': media_json}
@ -512,6 +511,8 @@ def send_media_group(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(
token, method_url, params=payload,
method='post' if files else 'get',
@ -523,7 +524,8 @@ def send_location(
live_period=None, reply_to_message_id=None,
reply_markup=None, disable_notification=None,
timeout=None, horizontal_accuracy=None, heading=None,
proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None):
proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None):
method_url = r'sendLocation'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
if live_period:
@ -546,6 +548,8 @@ def send_location(
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
@ -597,7 +601,7 @@ def send_venue(
foursquare_id=None, foursquare_type=None, disable_notification=None,
reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, google_place_id=None,
google_place_type=None, protect_content=None):
google_place_type=None, protect_content=None, message_thread_id=None):
method_url = r'sendVenue'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address}
if foursquare_id:
@ -620,13 +624,15 @@ def send_venue(
payload['google_place_type'] = google_place_type
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
def send_contact(
token, chat_id, phone_number, first_name, last_name=None, vcard=None,
disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, protect_content=None):
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
method_url = r'sendContact'
payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name}
if last_name:
@ -645,21 +651,26 @@ def send_contact(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
def send_chat_action(token, chat_id, action, timeout=None):
def send_chat_action(token, chat_id, action, timeout=None, message_thread_id=None):
method_url = r'sendChatAction'
payload = {'chat_id': chat_id, 'action': action}
if timeout:
payload['timeout'] = timeout
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None, protect_content=None):
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
thumbnail=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None, has_spoiler=None):
method_url = r'sendVideo'
payload = {'chat_id': chat_id}
files = None
@ -683,14 +694,14 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumb:
if not util.is_string(thumb):
if thumbnail:
if not util.is_string(thumbnail):
if files:
files['thumb'] = thumb
files['thumbnail'] = thumbnail
else:
files = {'thumb': thumb}
files = {'thumbnail': thumbnail}
else:
payload['thumb'] = thumb
payload['thumbnail'] = thumbnail
if width:
payload['width'] = width
if height:
@ -701,13 +712,18 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if has_spoiler is not None:
payload['has_spoiler'] = has_spoiler
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_animation(
token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, thumb=None, caption_entities=None,
allow_sending_without_reply=None, protect_content=None, width=None, height=None):
parse_mode=None, disable_notification=None, timeout=None, thumbnail=None, caption_entities=None,
allow_sending_without_reply=None, protect_content=None, width=None, height=None, message_thread_id=None,
has_spoiler=None):
method_url = r'sendAnimation'
payload = {'chat_id': chat_id}
files = None
@ -729,14 +745,14 @@ def send_animation(
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumb:
if not util.is_string(thumb):
if thumbnail:
if not util.is_string(thumbnail):
if files:
files['thumb'] = thumb
files['thumbnail'] = thumbnail
else:
files = {'thumb': thumb}
files = {'thumbnail': thumbnail}
else:
payload['thumb'] = thumb
payload['thumbnail'] = thumbnail
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
@ -747,12 +763,16 @@ def send_animation(
payload['width'] = width
if height:
payload['height'] = height
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if has_spoiler is not None:
payload['has_spoiler'] = has_spoiler
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, caption_entities=None,
allow_sending_without_reply=None, protect_content=None):
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
method_url = r'sendVoice'
payload = {'chat_id': chat_id}
files = None
@ -780,11 +800,14 @@ def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_mess
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None, protect_content=None):
disable_notification=None, timeout=None, thumbnail=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None):
method_url = r'sendVideoNote'
payload = {'chat_id': chat_id}
files = None
@ -806,24 +829,26 @@ def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_m
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumb:
if not util.is_string(thumb):
if thumbnail:
if not util.is_string(thumbnail):
if files:
files['thumb'] = thumb
files['thumbnail'] = thumbnail
else:
files = {'thumb': thumb}
files = {'thumbnail': thumbnail}
else:
payload['thumb'] = thumb
payload['thumbnail'] = thumbnail
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None, reply_to_message_id=None,
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None,
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumbnail=None,
caption_entities=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
method_url = r'sendAudio'
payload = {'chat_id': chat_id}
files = None
@ -849,27 +874,29 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumb:
if not util.is_string(thumb):
if thumbnail:
if not util.is_string(thumbnail):
if files:
files['thumb'] = thumb
files['thumbnail'] = thumbnail
else:
files = {'thumb': thumb}
files = {'thumbnail': thumbnail}
else:
payload['thumb'] = thumb
payload['thumbnail'] = thumbnail
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None, parse_mode=None,
disable_notification=None, timeout=None, caption=None, thumb=None, caption_entities=None,
disable_notification=None, timeout=None, caption=None, thumbnail=None, caption_entities=None,
allow_sending_without_reply=None, disable_content_type_detection=None, visible_file_name=None,
protect_content = None):
protect_content = None, message_thread_id=None, emoji=None):
method_url = get_method_by_type(data_type)
payload = {'chat_id': chat_id}
files = None
@ -892,14 +919,14 @@ def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_m
payload['timeout'] = timeout
if caption:
payload['caption'] = caption
if thumb:
if not util.is_string(thumb):
if thumbnail:
if not util.is_string(thumbnail):
if files:
files['thumb'] = thumb
files['thumbnail'] = thumbnail
else:
files = {'thumb': thumb}
files = {'thumbnail': thumbnail}
else:
payload['thumb'] = thumb
payload['thumbnail'] = thumbnail
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
@ -908,6 +935,10 @@ def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_m
payload['protect_content'] = protect_content
if method_url == 'sendDocument' and disable_content_type_detection is not None:
payload['disable_content_type_detection'] = disable_content_type_detection
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if emoji:
payload['emoji'] = emoji
return _make_request(token, method_url, params=payload, files=files, method='post')
@ -939,36 +970,19 @@ def unban_chat_member(token, chat_id, user_id, only_if_banned):
def restrict_chat_member(
token, chat_id, user_id, until_date=None,
can_send_messages=None, can_send_media_messages=None,
can_send_polls=None, can_send_other_messages=None,
can_add_web_page_previews=None, can_change_info=None,
can_invite_users=None, can_pin_messages=None):
token, chat_id, user_id, permissions, until_date=None,
use_independent_chat_permissions=None):
method_url = 'restrictChatMember'
permissions = {}
if can_send_messages is not None:
permissions['can_send_messages'] = can_send_messages
if can_send_media_messages is not None:
permissions['can_send_media_messages'] = can_send_media_messages
if can_send_polls is not None:
permissions['can_send_polls'] = can_send_polls
if can_send_other_messages is not None:
permissions['can_send_other_messages'] = can_send_other_messages
if can_add_web_page_previews is not None:
permissions['can_add_web_page_previews'] = can_add_web_page_previews
if can_change_info is not None:
permissions['can_change_info'] = can_change_info
if can_invite_users is not None:
permissions['can_invite_users'] = can_invite_users
if can_pin_messages is not None:
permissions['can_pin_messages'] = can_pin_messages
permissions_json = json.dumps(permissions)
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions_json}
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions.to_json()}
if use_independent_chat_permissions is not None:
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
if until_date is not None:
if isinstance(until_date, datetime):
payload['until_date'] = until_date.timestamp()
else:
payload['until_date'] = until_date
return _make_request(token, method_url, params=payload, method='post')
@ -976,7 +990,8 @@ def promote_chat_member(
token, chat_id, user_id, can_change_info=None, can_post_messages=None,
can_edit_messages=None, can_delete_messages=None, can_invite_users=None,
can_restrict_members=None, can_pin_messages=None, can_promote_members=None,
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None):
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None,
can_manage_topics=None):
method_url = 'promoteChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
if can_change_info is not None:
@ -1001,6 +1016,8 @@ def promote_chat_member(
payload['can_manage_chat'] = can_manage_chat
if can_manage_video_chats is not None:
payload['can_manage_video_chats'] = can_manage_video_chats
if can_manage_topics is not None:
payload['can_manage_topics'] = can_manage_topics
return _make_request(token, method_url, params=payload, method='post')
@ -1024,12 +1041,14 @@ def unban_chat_sender_chat(token, chat_id, sender_chat_id):
return _make_request(token, method_url, params=payload, method='post')
def set_chat_permissions(token, chat_id, permissions):
def set_chat_permissions(token, chat_id, permissions, use_independent_chat_permissions=None):
method_url = 'setChatPermissions'
payload = {
'chat_id': chat_id,
'permissions': permissions.to_json()
}
if use_independent_chat_permissions is not None:
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
return _make_request(token, method_url, params=payload, method='post')
@ -1135,6 +1154,39 @@ def set_chat_title(token, chat_id, title):
return _make_request(token, method_url, params=payload, method='post')
def set_my_description(token, description=None, language_code=None):
method_url = r'setMyDescription'
payload = {}
if description is not None:
payload['description'] = description
if language_code is not None:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload, method='post')
def get_my_description(token, language_code=None):
method_url = r'getMyDescription'
payload = {}
if language_code:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload)
def set_my_short_description(token, short_description=None, language_code=None):
method_url = r'setMyShortDescription'
payload = {}
if short_description is not None:
payload['short_description'] = short_description
if language_code is not None:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload, method='post')
def get_my_short_description(token, language_code=None):
method_url = r'getMyShortDescription'
payload = {}
if language_code:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload)
def get_my_commands(token, scope=None, language_code=None):
method_url = r'getMyCommands'
payload = {}
@ -1144,6 +1196,22 @@ def get_my_commands(token, scope=None, language_code=None):
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload)
def set_my_name(token, name=None, language_code=None):
method_url = r'setMyName'
payload = {}
if name is not None:
payload['name'] = name
if language_code is not None:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload, method='post')
def get_my_name(token, language_code=None):
method_url = r'getMyName'
payload = {}
if language_code is not None:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload)
def set_chat_menu_button(token, chat_id=None, menu_button=None):
method_url = r'setChatMenuButton'
payload = {}
@ -1313,7 +1381,7 @@ def delete_message(token, chat_id, message_id, timeout=None):
def send_game(
token, chat_id, game_short_name,
disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, protect_content=None):
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
method_url = r'sendGame'
payload = {'chat_id': chat_id, 'game_short_name': game_short_name}
if disable_notification is not None:
@ -1328,6 +1396,8 @@ def send_game(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
@ -1393,7 +1463,7 @@ def send_invoice(
send_phone_number_to_provider = None, send_email_to_provider = None, is_flexible=None,
disable_notification=None, reply_to_message_id=None, reply_markup=None, provider_data=None,
timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None,
protect_content=None):
protect_content=None, message_thread_id=None):
"""
Use this method to send invoices. On success, the sent Message is returned.
:param token: Bot's token (you don't need to fill this)
@ -1425,7 +1495,8 @@ def send_invoice(
:param max_tip_amount: The maximum accepted amount for tips in the smallest units of the currency
:param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the smallest units of the currency.
At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount.
:param protect_content:
:param protect_content: Protects the contents of the sent message from forwarding and saving
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
:return:
"""
method_url = r'sendInvoice'
@ -1474,6 +1545,8 @@ def send_invoice(
payload['suggested_tip_amounts'] = json.dumps(suggested_tip_amounts)
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
@ -1541,7 +1614,7 @@ def answer_callback_query(token, callback_query_id, text=None, show_alert=None,
def answer_inline_query(token, inline_query_id, results, cache_time=None, is_personal=None, next_offset=None,
switch_pm_text=None, switch_pm_parameter=None):
button=None):
method_url = 'answerInlineQuery'
payload = {'inline_query_id': inline_query_id, 'results': _convert_list_json_serializable(results)}
if cache_time is not None:
@ -1550,10 +1623,8 @@ def answer_inline_query(token, inline_query_id, results, cache_time=None, is_per
payload['is_personal'] = is_personal
if next_offset is not None:
payload['next_offset'] = next_offset
if switch_pm_text:
payload['switch_pm_text'] = switch_pm_text
if switch_pm_parameter:
payload['switch_pm_parameter'] = switch_pm_parameter
if button is not None:
payload["button"] = button.to_json()
return _make_request(token, method_url, params=payload, method='post')
@ -1563,58 +1634,86 @@ def get_sticker_set(token, name):
def get_custom_emoji_stickers(token, custom_emoji_ids):
method_url = r'getCustomEmojiStickers'
return _make_request(token, method_url, params={'custom_emoji_ids': custom_emoji_ids})
return _make_request(token, method_url, params={'custom_emoji_ids': json.dumps(custom_emoji_ids)})
def set_sticker_keywords(token, sticker, keywords=None):
method_url = 'setStickerKeywords'
payload = {'sticker': sticker}
if keywords:
payload['keywords'] = json.dumps(keywords)
return _make_request(token, method_url, params=payload, method='post')
def set_sticker_mask_position(token, sticker, mask_position=None):
method_url = 'setStickerMaskPosition'
payload = {'sticker': sticker}
if mask_position:
payload['mask_position'] = mask_position.to_json()
return _make_request(token, method_url, params=payload, method='post')
def upload_sticker_file(token, user_id, png_sticker):
def upload_sticker_file(token, user_id, sticker, sticker_format):
method_url = 'uploadStickerFile'
payload = {'user_id': user_id}
files = {'png_sticker': png_sticker}
payload = {'user_id': user_id, 'sticker_format': sticker_format}
files = {'sticker': sticker}
return _make_request(token, method_url, params=payload, files=files, method='post')
def set_custom_emoji_sticker_set_thumbnail(token, name, custom_emoji_id=None):
method_url = 'setCustomEmojiStickerSetThumbnail'
payload = {'name': name}
if custom_emoji_id is not None:
payload['custom_emoji_id'] = custom_emoji_id
return _make_request(token, method_url, params=payload, method='post')
def set_sticker_set_title(token, name, title):
method_url = 'setStickerSetTitle'
payload = {'name': name, 'title': title}
return _make_request(token, method_url, params=payload, method='post')
def delete_sticker_set(token, name):
method_url = 'deleteStickerSet'
payload = {'name': name}
return _make_request(token, method_url, params=payload, method='post')
def set_sticker_emoji_list(token, sticker, emoji_list):
method_url = 'setStickerEmojiList'
payload = {'sticker': sticker, 'emoji_list': json.dumps(emoji_list)}
return _make_request(token, method_url, params=payload, method='post')
def create_new_sticker_set(
token, user_id, name, title, emojis, png_sticker, tgs_sticker,
mask_position=None, webm_sticker=None, sticker_type=None):
token, user_id, name, title, stickers, sticker_format, sticker_type=None, needs_repainting=None):
method_url = 'createNewStickerSet'
payload = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis}
if png_sticker:
stype = 'png_sticker'
elif webm_sticker:
stype = 'webm_sticker'
else:
stype = 'tgs_sticker'
sticker = png_sticker or tgs_sticker or webm_sticker
files = None
if not util.is_string(sticker):
files = {stype: sticker}
else:
payload[stype] = sticker
if mask_position:
payload['mask_position'] = mask_position.to_json()
if webm_sticker:
payload['webm_sticker'] = webm_sticker
payload = {'user_id': user_id, 'name': name, 'title': title, 'sticker_format': sticker_format}
if sticker_type:
payload['sticker_type'] = sticker_type
if needs_repainting:
payload['needs_repainting'] = needs_repainting
files = {}
lst = []
for sticker in stickers:
json_dict, file = sticker.convert_input_sticker()
json_dict = sticker.to_dict()
if file:
list_keys = list(file.keys())
files[list_keys[0]] = file[list_keys[0]]
lst.append(json_dict)
payload['stickers'] = json.dumps(lst)
return _make_request(token, method_url, params=payload, files=files, method='post')
def add_sticker_to_set(token, user_id, name, emojis, png_sticker, tgs_sticker, mask_position, webm_sticker):
def add_sticker_to_set(token, user_id, name, sticker):
method_url = 'addStickerToSet'
payload = {'user_id': user_id, 'name': name, 'emojis': emojis}
if png_sticker:
stype = 'png_sticker'
elif webm_sticker:
stype = 'webm_sticker'
else:
stype = 'tgs_sticker'
sticker = png_sticker or tgs_sticker or webm_sticker
files = None
if not util.is_string(sticker):
files = {stype: sticker}
else:
payload[stype] = sticker
if mask_position:
payload['mask_position'] = mask_position.to_json()
json_dict, files = sticker.convert_input_sticker()
payload = {'user_id': user_id, 'name': name, 'sticker': json_dict}
return _make_request(token, method_url, params=payload, files=files, method='post')
@ -1682,7 +1781,7 @@ def send_poll(
is_anonymous = None, type = None, allows_multiple_answers = None, correct_option_id = None,
explanation = None, explanation_parse_mode=None, open_period = None, close_date = None, is_closed = None,
disable_notification=False, reply_to_message_id=None, allow_sending_without_reply=None,
reply_markup=None, timeout=None, explanation_entities=None, protect_content=None):
reply_markup=None, timeout=None, explanation_entities=None, protect_content=None, message_thread_id=None):
method_url = r'sendPoll'
payload = {
'chat_id': str(chat_id),
@ -1726,8 +1825,51 @@ def send_poll(
types.MessageEntity.to_list_of_dicts(explanation_entities))
if protect_content:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
def create_forum_topic(token, chat_id, name, icon_color=None, icon_custom_emoji_id=None):
method_url = r'createForumTopic'
payload = {'chat_id': chat_id, 'name': name}
if icon_color:
payload['icon_color'] = icon_color
if icon_custom_emoji_id:
payload['icon_custom_emoji_id'] = icon_custom_emoji_id
return _make_request(token, method_url, params=payload)
def edit_forum_topic(token, chat_id, message_thread_id, name=None, icon_custom_emoji_id=None):
method_url = r'editForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
if name is not None:
payload['name'] = name
if icon_custom_emoji_id is not None:
payload['icon_custom_emoji_id'] = icon_custom_emoji_id
return _make_request(token, method_url, params=payload)
def close_forum_topic(token, chat_id, message_thread_id):
method_url = r'closeForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return _make_request(token, method_url, params=payload)
def reopen_forum_topic(token, chat_id, message_thread_id):
method_url = r'reopenForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return _make_request(token, method_url, params=payload)
def delete_forum_topic(token, chat_id, message_thread_id):
method_url = r'deleteForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return _make_request(token, method_url, params=payload)
def unpin_all_forum_topic_messages(token, chat_id, message_thread_id):
method_url = r'unpinAllForumTopicMessages'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return _make_request(token, method_url, params=payload)
def get_forum_topic_icon_stickers(token):
method_url = r'getForumTopicIconStickers'
return _make_request(token, method_url)
def stop_poll(token, chat_id, message_id, reply_markup=None):
method_url = r'stopPoll'
@ -1736,6 +1878,31 @@ def stop_poll(token, chat_id, message_id, reply_markup=None):
payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload)
def edit_general_forum_topic(token, chat_id, name):
method_url = r'editGeneralForumTopic'
payload = {'chat_id': chat_id, 'name': name}
return _make_request(token, method_url, params=payload)
def close_general_forum_topic(token, chat_id):
method_url = r'closeGeneralForumTopic'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload)
def reopen_general_forum_topic(token, chat_id):
method_url = r'reopenGeneralForumTopic'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload)
def hide_general_forum_topic(token, chat_id):
method_url = r'hideGeneralForumTopic'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload)
def unhide_general_forum_topic(token, chat_id):
method_url = r'unhideGeneralForumTopic'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload)
def _convert_list_json_serializable(results):
ret = ''

File diff suppressed because it is too large Load Diff

View File

@ -420,7 +420,7 @@ class StateFilter(AdvancedCustomFilter):
text = text.name
if message.chat.type in ['group', 'supergroup']:
group_state = await self.bot.current_states.get_state(user_id, chat_id)
group_state = await self.bot.current_states.get_state(chat_id, user_id)
if group_state == text:
return True
elif type(text) is list and group_state in text:
@ -428,7 +428,7 @@ class StateFilter(AdvancedCustomFilter):
else:
user_state = await self.bot.current_states.get_state(user_id, chat_id)
user_state = await self.bot.current_states.get_state(chat_id, user_id)
if user_state == text:
return True
elif type(text) is list and user_state in text:

View File

@ -3,8 +3,6 @@ File with all middleware classes, states.
"""
class BaseMiddleware:
"""
Base class for middleware.
@ -76,12 +74,18 @@ class StatesGroup:
my_state = State() # returns my_state:State string.
"""
def __init_subclass__(cls) -> None:
state_list = []
for name, value in cls.__dict__.items():
if not name.startswith('__') and not callable(value) and isinstance(value, State):
# change value of that variable
value.name = ':'.join((cls.__name__, name))
value.group = cls
state_list.append(value)
cls._state_list = state_list
@property
def state_list(self):
return self._state_list
class SkipHandler:
@ -96,6 +100,7 @@ class SkipHandler:
def __init__(self) -> None:
pass
class CancelUpdate:
"""
Class for canceling updates.
@ -106,4 +111,27 @@ class CancelUpdate:
"""
def __init__(self) -> None:
pass
pass
class ContinueHandling:
"""
Class for continue updates in handlers.
Just return instance of this class
in handlers to continue process.
.. code-block:: python3
:caption: Example of using ContinueHandling
@bot.message_handler(commands=['start'])
async def start(message):
await bot.send_message(message.chat.id, 'Hello World!')
return ContinueHandling()
@bot.message_handler(commands=['start'])
async def start2(message):
await bot.send_message(message.chat.id, 'Hello World2!')
"""
def __init__(self) -> None:
pass

View File

@ -13,15 +13,17 @@ API_URL = 'https://api.telegram.org/bot{0}/{1}'
from datetime import datetime
from telebot import util, logger
from telebot import util
import logging
logger = logging.getLogger('TeleBot')
proxy = None
session = None
FILE_URL = None
REQUEST_TIMEOUT = None
REQUEST_TIMEOUT = 300
MAX_RETRIES = 3
REQUEST_LIMIT = 50
@ -56,10 +58,29 @@ class SessionManager:
session_manager = SessionManager()
async def _process_request(token, url, method='get', params=None, files=None, request_timeout=None):
async def _process_request(token, url, method='get', params=None, files=None, **kwargs):
# Let's resolve all timeout parameters.
# getUpdates parameter may contain 2 parameters: request_timeout & timeout.
# other methods may contain timeout parameter that should be applied to
# ClientTimeout only.
# timeout should be added to params for getUpdates. All other timeout's should be used
# for request timeout.
# here we got request_timeout, so this is getUpdates method.
if 'request_timeout' in kwargs:
request_timeout = kwargs.pop('request_timeout')
else:
# let's check for timeout in params
request_timeout = params.pop('timeout', None) if params else None
# we will apply default request_timeout if there is no timeout in params
# otherwise, we will use timeout parameter applied for payload.
request_timeout = REQUEST_TIMEOUT if request_timeout is None else request_timeout
# Preparing data by adding all parameters and files to FormData
params = _prepare_data(params, files)
if request_timeout is None:
request_timeout = REQUEST_TIMEOUT
timeout = aiohttp.ClientTimeout(total=request_timeout)
got_result = False
current_try=0
@ -150,10 +171,10 @@ async def get_file(token, file_id):
async def get_file_url(token, file_id):
if FILE_URL is None:
return "https://api.telegram.org/file/bot{0}/{1}".format(token, await get_file(token, file_id)['file_path'])
return "https://api.telegram.org/file/bot{0}/{1}".format(token, (await get_file(token, file_id))['file_path'])
else:
# noinspection PyUnresolvedReferences
return FILE_URL.format(token, await get_file(token, file_id)['file_path'])
return FILE_URL.format(token, (await get_file(token, file_id))['file_path'])
async def download_file(token, file_path):
@ -162,12 +183,12 @@ async def download_file(token, file_path):
else:
# noinspection PyUnresolvedReferences
url = FILE_URL.format(token, file_path)
async with await session_manager.get_session() as session:
async with session.get(url, proxy=proxy) as response:
result = await response.read()
if response.status != 200:
raise ApiHTTPException('Download file', result)
session = await session_manager.get_session()
async with session.get(url, proxy=proxy) as response:
if response.status != 200:
raise ApiHTTPException('Download file', response)
result = await response.read()
return result
@ -224,11 +245,11 @@ async def get_updates(token, offset=None, limit=None,
params['limit'] = limit
if timeout:
params['timeout'] = timeout
if allowed_updates:
params['allowed_updates'] = allowed_updates
if allowed_updates is not None: # Empty lists should pass
params['allowed_updates'] = json.dumps(allowed_updates)
return await _process_request(token, method_name, params=params, request_timeout=request_timeout)
async def _check_result(method_name, result):
async def _check_result(method_name, result: aiohttp.ClientResponse):
"""
Checks whether `result` is a valid API response.
A result is considered invalid if:
@ -244,7 +265,7 @@ async def _check_result(method_name, result):
try:
result_json = await result.json(encoding="utf-8")
except:
if result.status_code != 200:
if result.status != 200:
raise ApiHTTPException(method_name, result)
else:
raise ApiInvalidJSONException(method_name, result)
@ -259,23 +280,8 @@ async def send_message(
token, chat_id, text,
disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
entities=None, allow_sending_without_reply=None, protect_content=None):
"""
Use this method to send text messages. On success, the sent Message is returned.
:param token:
:param chat_id:
:param text:
:param disable_web_page_preview:
:param reply_to_message_id:
:param reply_markup:
:param parse_mode:
:param disable_notification:
:param timeout:
:param entities:
:param allow_sending_without_reply:
:param protect_content:
:return:
"""
entities=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None):
method_name = 'sendMessage'
params = {'chat_id': str(chat_id), 'text': text}
if disable_web_page_preview is not None:
@ -296,6 +302,8 @@ async def send_message(
params['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
params['protect_content'] = protect_content
if message_thread_id:
params['message_thread_id'] = message_thread_id
return await _process_request(token, method_name, params=params)
@ -335,15 +343,15 @@ async def get_chat_member_count(token, chat_id):
return await _process_request(token, method_url, params=payload)
async def set_sticker_set_thumb(token, name, user_id, thumb):
method_url = r'setStickerSetThumb'
async def set_sticker_set_thumbnail(token, name, user_id, thumbnail):
method_url = r'setStickerSetThumbnail'
payload = {'name': name, 'user_id': user_id}
files = {}
if thumb:
if not isinstance(thumb, str):
files['thumb'] = thumb
if thumbnail:
if not isinstance(thumbnail, str):
files['thumbnail'] = thumbnail
else:
payload['thumb'] = thumb
payload['thumbnail'] = thumbnail
return await _process_request(token, method_url, params=payload, files=files or None)
@ -373,7 +381,8 @@ async def get_chat_member(token, chat_id, user_id):
async def forward_message(
token, chat_id, from_chat_id, message_id,
disable_notification=None, timeout=None, protect_content=None):
disable_notification=None, timeout=None, protect_content=None,
message_thread_id=None):
method_url = r'forwardMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if disable_notification is not None:
@ -382,12 +391,14 @@ async def forward_message(
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
async def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_mode=None, caption_entities=None,
disable_notification=None, reply_to_message_id=None, allow_sending_without_reply=None,
reply_markup=None, timeout=None, protect_content=None):
reply_markup=None, timeout=None, protect_content=None, message_thread_id=None):
method_url = r'copyMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if caption is not None:
@ -408,13 +419,16 @@ async def copy_message(token, chat_id, from_chat_id, message_id, caption=None, p
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
async def send_dice(
token, chat_id,
emoji=None, disable_notification=None, reply_to_message_id=None,
reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None):
reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None):
method_url = r'sendDice'
payload = {'chat_id': chat_id}
if emoji:
@ -431,6 +445,8 @@ async def send_dice(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
@ -438,7 +454,8 @@ async def send_photo(
token, chat_id, photo,
caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
caption_entities=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None, has_spoiler=None):
method_url = r'sendPhoto'
payload = {'chat_id': chat_id}
files = None
@ -466,13 +483,17 @@ async def send_photo(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if has_spoiler is not None:
payload['has_spoiler'] = has_spoiler
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_media_group(
token, chat_id, media,
disable_notification=None, reply_to_message_id=None,
timeout=None, allow_sending_without_reply=None, protect_content=None):
timeout=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
method_url = r'sendMediaGroup'
media_json, files = await convert_input_media_array(media)
payload = {'chat_id': chat_id, 'media': media_json}
@ -486,6 +507,8 @@ async def send_media_group(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(
token, method_url, params=payload,
method='post' if files else 'get',
@ -497,7 +520,7 @@ async def send_location(
live_period=None, reply_to_message_id=None,
reply_markup=None, disable_notification=None,
timeout=None, horizontal_accuracy=None, heading=None,
proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None):
proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
method_url = r'sendLocation'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
if live_period:
@ -520,6 +543,8 @@ async def send_location(
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
@ -571,7 +596,7 @@ async def send_venue(
foursquare_id=None, foursquare_type=None, disable_notification=None,
reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, google_place_id=None,
google_place_type=None, protect_content=None):
google_place_type=None, protect_content=None, message_thread_id=None):
method_url = r'sendVenue'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address}
if foursquare_id:
@ -594,13 +619,15 @@ async def send_venue(
payload['google_place_type'] = google_place_type
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
async def send_contact(
token, chat_id, phone_number, first_name, last_name=None, vcard=None,
disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, protect_content=None):
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
method_url = r'sendContact'
payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name}
if last_name:
@ -619,21 +646,25 @@ async def send_contact(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
async def send_chat_action(token, chat_id, action, timeout=None):
async def send_chat_action(token, chat_id, action, timeout=None, message_thread_id=None):
method_url = r'sendChatAction'
payload = {'chat_id': chat_id, 'action': action}
if timeout:
payload['timeout'] = timeout
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
async def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None,
protect_content=None):
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
thumbnail=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None,
protect_content=None, message_thread_id=None, has_spoiler=None):
method_url = r'sendVideo'
payload = {'chat_id': chat_id}
files = None
@ -657,14 +688,14 @@ async def send_video(token, chat_id, data, duration=None, caption=None, reply_to
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumb:
if not util.is_string(thumb):
if thumbnail:
if not util.is_string(thumbnail):
if files:
files['thumb'] = thumb
files['thumbnail'] = thumbnail
else:
files = {'thumb': thumb}
files = {'thumbnail': thumbnail}
else:
payload['thumb'] = thumb
payload['thumbnail'] = thumbnail
if width:
payload['width'] = width
if height:
@ -675,13 +706,18 @@ async def send_video(token, chat_id, data, duration=None, caption=None, reply_to
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if has_spoiler is not None:
payload['has_spoiler'] = has_spoiler
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_animation(
token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, thumb=None, caption_entities=None,
allow_sending_without_reply=None, width=None, height=None, protect_content=None):
parse_mode=None, disable_notification=None, timeout=None, thumbnail=None, caption_entities=None,
allow_sending_without_reply=None, width=None, height=None, protect_content=None, message_thread_id=None,
has_spoiler=None):
method_url = r'sendAnimation'
payload = {'chat_id': chat_id}
files = None
@ -703,14 +739,14 @@ async def send_animation(
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumb:
if not util.is_string(thumb):
if thumbnail:
if not util.is_string(thumbnail):
if files:
files['thumb'] = thumb
files['thumbnail'] = thumbnail
else:
files = {'thumb': thumb}
files = {'thumbnail': thumbnail}
else:
payload['thumb'] = thumb
payload['thumbnail'] = thumbnail
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
@ -721,12 +757,16 @@ async def send_animation(
payload['height'] = height
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if has_spoiler is not None:
payload['has_spoiler'] = has_spoiler
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, caption_entities=None,
allow_sending_without_reply=None, protect_content=None):
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
method_url = r'sendVoice'
payload = {'chat_id': chat_id}
files = None
@ -754,11 +794,14 @@ async def send_voice(token, chat_id, voice, caption=None, duration=None, reply_t
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None, protect_content=None):
disable_notification=None, timeout=None, thumbnail=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None):
method_url = r'sendVideoNote'
payload = {'chat_id': chat_id}
files = None
@ -780,24 +823,26 @@ async def send_video_note(token, chat_id, data, duration=None, length=None, repl
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumb:
if not util.is_string(thumb):
if thumbnail:
if not util.is_string(thumbnail):
if files:
files['thumb'] = thumb
files['thumbnail'] = thumbnail
else:
files = {'thumb': thumb}
files = {'thumbnail': thumbnail}
else:
payload['thumb'] = thumb
payload['thumbnail'] = thumbnail
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None, reply_to_message_id=None,
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None,
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumbnail=None,
caption_entities=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
method_url = r'sendAudio'
payload = {'chat_id': chat_id}
files = None
@ -823,26 +868,29 @@ async def send_audio(token, chat_id, audio, caption=None, duration=None, perform
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumb:
if not util.is_string(thumb):
if thumbnail:
if not util.is_string(thumbnail):
if files:
files['thumb'] = thumb
files['thumbnail'] = thumbnail
else:
files = {'thumb': thumb}
files = {'thumbnail': thumbnail}
else:
payload['thumb'] = thumb
payload['thumbnail'] = thumbnail
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None, parse_mode=None,
disable_notification=None, timeout=None, caption=None, thumb=None, caption_entities=None,
allow_sending_without_reply=None, disable_content_type_detection=None, visible_file_name=None, protect_content=None):
disable_notification=None, timeout=None, caption=None, thumbnail=None, caption_entities=None,
allow_sending_without_reply=None, disable_content_type_detection=None, visible_file_name=None, protect_content=None,
message_thread_id=None, emoji=None):
method_url = await get_method_by_type(data_type)
payload = {'chat_id': chat_id}
files = None
@ -865,14 +913,14 @@ async def send_data(token, chat_id, data, data_type, reply_to_message_id=None, r
payload['timeout'] = timeout
if caption:
payload['caption'] = caption
if thumb:
if not util.is_string(thumb):
if thumbnail:
if not util.is_string(thumbnail):
if files:
files['thumb'] = thumb
files['thumbnail'] = thumbnail
else:
files = {'thumb': thumb}
files = {'thumbnail': thumbnail}
else:
payload['thumb'] = thumb
payload['thumbnail'] = thumbnail
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
@ -881,6 +929,10 @@ async def send_data(token, chat_id, data, data_type, reply_to_message_id=None, r
payload['protect_content'] = protect_content
if method_url == 'sendDocument' and disable_content_type_detection is not None:
payload['disable_content_type_detection'] = disable_content_type_detection
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if emoji:
payload['emoji'] = emoji
return await _process_request(token, method_url, params=payload, files=files, method='post')
@ -912,31 +964,13 @@ async def unban_chat_member(token, chat_id, user_id, only_if_banned):
async def restrict_chat_member(
token, chat_id, user_id, until_date=None,
can_send_messages=None, can_send_media_messages=None,
can_send_polls=None, can_send_other_messages=None,
can_add_web_page_previews=None, can_change_info=None,
can_invite_users=None, can_pin_messages=None):
token, chat_id, user_id, permissions, until_date=None,
use_independent_chat_permissions=None):
method_url = 'restrictChatMember'
permissions = {}
if can_send_messages is not None:
permissions['can_send_messages'] = can_send_messages
if can_send_media_messages is not None:
permissions['can_send_media_messages'] = can_send_media_messages
if can_send_polls is not None:
permissions['can_send_polls'] = can_send_polls
if can_send_other_messages is not None:
permissions['can_send_other_messages'] = can_send_other_messages
if can_add_web_page_previews is not None:
permissions['can_add_web_page_previews'] = can_add_web_page_previews
if can_change_info is not None:
permissions['can_change_info'] = can_change_info
if can_invite_users is not None:
permissions['can_invite_users'] = can_invite_users
if can_pin_messages is not None:
permissions['can_pin_messages'] = can_pin_messages
permissions_json = json.dumps(permissions)
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions_json}
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions.to_json()}
if use_independent_chat_permissions is not None:
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
if until_date is not None:
if isinstance(until_date, datetime):
payload['until_date'] = until_date.timestamp()
@ -949,7 +983,7 @@ async def promote_chat_member(
token, chat_id, user_id, can_change_info=None, can_post_messages=None,
can_edit_messages=None, can_delete_messages=None, can_invite_users=None,
can_restrict_members=None, can_pin_messages=None, can_promote_members=None,
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None):
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None, can_manage_topics=None):
method_url = 'promoteChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
if can_change_info is not None:
@ -974,6 +1008,8 @@ async def promote_chat_member(
payload['can_manage_chat'] = can_manage_chat
if can_manage_video_chats is not None:
payload['can_manage_video_chats'] = can_manage_video_chats
if can_manage_topics is not None:
payload['can_manage_topics'] = can_manage_topics
return await _process_request(token, method_url, params=payload, method='post')
@ -996,12 +1032,14 @@ async def unban_chat_sender_chat(token, chat_id, sender_chat_id):
payload = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}
return await _process_request(token, method_url, params=payload, method='post')
async def set_chat_permissions(token, chat_id, permissions):
async def set_chat_permissions(token, chat_id, permissions, use_independent_chat_permissions=None):
method_url = 'setChatPermissions'
payload = {
'chat_id': chat_id,
'permissions': permissions.to_json()
}
if use_independent_chat_permissions is not None:
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
return await _process_request(token, method_url, params=payload, method='post')
@ -1104,6 +1142,37 @@ async def set_chat_title(token, chat_id, title):
payload = {'chat_id': chat_id, 'title': title}
return await _process_request(token, method_url, params=payload, method='post')
async def set_my_description(token, description=None, language_code=None):
method_url = r'setMyDescription'
payload = {}
if description is not None:
payload['description'] = description
if language_code is not None:
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload, method='post')
async def get_my_description(token, language_code=None):
method_url = r'getMyDescription'
payload = {}
if language_code:
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload)
async def set_my_short_description(token, short_description=None, language_code=None):
method_url = r'setMyShortDescription'
payload = {}
if short_description is not None:
payload['short_description'] = short_description
if language_code is not None:
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload, method='post')
async def get_my_short_description(token, language_code=None):
method_url = r'getMyShortDescription'
payload = {}
if language_code:
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload)
async def get_my_commands(token, scope=None, language_code=None):
method_url = r'getMyCommands'
@ -1114,6 +1183,23 @@ async def get_my_commands(token, scope=None, language_code=None):
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload)
async def set_my_name(token, name=None, language_code=None):
method_url = r'setMyName'
payload = {}
if name is not None:
payload['name'] = name
if language_code is not None:
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload, method='post')
async def get_my_name(token, language_code=None):
method_url = r'getMyName'
payload = {}
if language_code is not None:
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload)
async def set_chat_menu_button(token, chat_id=None, menu_button=None):
method_url = r'setChatMenuButton'
payload = {}
@ -1285,7 +1371,7 @@ async def delete_message(token, chat_id, message_id, timeout=None):
async def send_game(
token, chat_id, game_short_name,
disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, protect_content=None):
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
method_url = r'sendGame'
payload = {'chat_id': chat_id, 'game_short_name': game_short_name}
if disable_notification is not None:
@ -1300,6 +1386,8 @@ async def send_game(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
@ -1364,7 +1452,8 @@ async def send_invoice(
need_name=None, need_phone_number=None, need_email=None, need_shipping_address=None,
send_phone_number_to_provider = None, send_email_to_provider = None, is_flexible=None,
disable_notification=None, reply_to_message_id=None, reply_markup=None, provider_data=None,
timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None, protect_content=None):
timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None,
protect_content=None, message_thread_id=None):
"""
Use this method to send invoices. On success, the sent Message is returned.
:param token: Bot's token (you don't need to fill this)
@ -1396,7 +1485,8 @@ async def send_invoice(
:param max_tip_amount: The maximum accepted amount for tips in the smallest units of the currency
:param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the smallest units of the currency.
At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount.
:param protect_content:
:param protect_content: Protects the contents of the sent message from forwarding and saving
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
:return:
"""
method_url = r'sendInvoice'
@ -1445,6 +1535,8 @@ async def send_invoice(
payload['suggested_tip_amounts'] = json.dumps(suggested_tip_amounts)
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
@ -1512,7 +1604,7 @@ async def answer_callback_query(token, callback_query_id, text=None, show_alert=
async def answer_inline_query(token, inline_query_id, results, cache_time=None, is_personal=None, next_offset=None,
switch_pm_text=None, switch_pm_parameter=None):
button=None):
method_url = 'answerInlineQuery'
payload = {'inline_query_id': inline_query_id, 'results': await _convert_list_json_serializable(results)}
if cache_time is not None:
@ -1521,10 +1613,10 @@ async def answer_inline_query(token, inline_query_id, results, cache_time=None,
payload['is_personal'] = is_personal
if next_offset is not None:
payload['next_offset'] = next_offset
if switch_pm_text:
payload['switch_pm_text'] = switch_pm_text
if switch_pm_parameter:
payload['switch_pm_parameter'] = switch_pm_parameter
if button is not None:
payload["button"] = button.to_json()
return await _process_request(token, method_url, params=payload, method='post')
@ -1534,62 +1626,85 @@ async def get_sticker_set(token, name):
async def get_custom_emoji_stickers(token, custom_emoji_ids):
method_url = r'getCustomEmojiStickers'
return await _process_request(token, method_url, params={'custom_emoji_ids': custom_emoji_ids})
return await _process_request(token, method_url, params={'custom_emoji_ids': json.dumps(custom_emoji_ids)})
async def upload_sticker_file(token, user_id, png_sticker):
async def set_sticker_keywords(token, sticker, keywords=None):
method_url = 'setStickerKeywords'
payload = {'sticker': sticker}
if keywords:
payload['keywords'] = json.dumps(keywords)
return await _process_request(token, method_url, params=payload, method='post')
async def set_sticker_mask_position(token, sticker, mask_position=None):
method_url = 'setStickerMaskPosition'
payload = {'sticker': sticker}
if mask_position:
payload['mask_position'] = mask_position.to_json()
return await _process_request(token, method_url, params=payload, method='post')
async def upload_sticker_file(token, user_id, sticker, sticker_format):
method_url = 'uploadStickerFile'
payload = {'user_id': user_id}
files = {'png_sticker': png_sticker}
payload = {'user_id': user_id, 'sticker_format': sticker_format}
files = {'sticker': sticker}
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def set_sticker_emoji_list(token, sticker, emoji_list):
method_url = 'setStickerEmojiList'
payload = {'sticker': sticker, 'emoji_list': json.dumps(emoji_list)}
return await _process_request(token, method_url, params=payload, method='post')
async def delete_sticker_set(token, name):
method_url = 'deleteStickerSet'
payload = {'name': name}
return await _process_request(token, method_url, params=payload, method='post')
async def set_custom_emoji_sticker_set_thumbnail(token, name, custom_emoji_id=None):
method_url = 'setCustomEmojiStickerSetThumbnail'
payload = {'name': name}
if custom_emoji_id is not None:
payload['custom_emoji_id'] = custom_emoji_id
return await _process_request(token, method_url, params=payload, method='post')
async def set_sticker_set_title(token, name, title):
method_url = 'setStickerSetTitle'
payload = {'name': name, 'title': title}
return await _process_request(token, method_url, params=payload, method='post')
async def create_new_sticker_set(
token, user_id, name, title, emojis, png_sticker, tgs_sticker,
mask_position=None, webm_sticker=None, sticker_type=None):
token, user_id, name, title, stickers, sticker_format, sticker_type=None, needs_repainting=None):
method_url = 'createNewStickerSet'
payload = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis}
if png_sticker:
stype = 'png_sticker'
elif webm_sticker:
stype = 'webm_sticker'
else:
stype = 'tgs_sticker'
sticker = png_sticker or tgs_sticker or webm_sticker
files = None
if not util.is_string(sticker):
files = {stype: sticker}
else:
payload[stype] = sticker
if mask_position:
payload['mask_position'] = mask_position.to_json()
if webm_sticker:
payload['webm_sticker'] = webm_sticker
payload = {'user_id': user_id, 'name': name, 'title': title, 'sticker_format': sticker_format}
if sticker_type:
payload['sticker_type'] = sticker_type
if needs_repainting:
payload['needs_repainting'] = needs_repainting
files = {}
lst = []
for sticker in stickers:
json_dict, file = sticker.convert_input_sticker()
json_dict = sticker.to_dict()
if file:
list_keys = list(file.keys())
files[list_keys[0]] = file[list_keys[0]]
lst.append(json_dict)
payload['stickers'] = json.dumps(lst)
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def add_sticker_to_set(token, user_id, name, emojis, png_sticker, tgs_sticker, mask_position, webm_sticker):
async def add_sticker_to_set(token, user_id, name, sticker):
method_url = 'addStickerToSet'
payload = {'user_id': user_id, 'name': name, 'emojis': emojis}
if png_sticker:
stype = 'png_sticker'
elif webm_sticker:
stype = 'webm_sticker'
else:
stype = 'tgs_sticker'
files = None
sticker = png_sticker or tgs_sticker or webm_sticker
json_dict, files = sticker.convert_input_sticker()
payload = {'user_id': user_id, 'name': name, 'sticker': json_dict}
if not util.is_string(sticker):
files = {stype: sticker}
else:
payload[stype] = sticker
if mask_position:
payload['mask_position'] = mask_position.to_json()
if webm_sticker:
payload['webm_sticker'] = webm_sticker
return await _process_request(token, method_url, params=payload, files=files, method='post')
@ -1653,7 +1768,7 @@ async def send_poll(
is_anonymous = None, type = None, allows_multiple_answers = None, correct_option_id = None,
explanation = None, explanation_parse_mode=None, open_period = None, close_date = None, is_closed = None,
disable_notification=False, reply_to_message_id=None, allow_sending_without_reply=None,
reply_markup=None, timeout=None, explanation_entities=None, protect_content=None):
reply_markup=None, timeout=None, explanation_entities=None, protect_content=None, message_thread_id=None):
method_url = r'sendPoll'
payload = {
'chat_id': str(chat_id),
@ -1697,6 +1812,76 @@ async def send_poll(
types.MessageEntity.to_list_of_dicts(explanation_entities))
if protect_content:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
async def create_forum_topic(token, chat_id, name, icon_color=None, icon_custom_emoji_id=None):
method_url = r'createForumTopic'
payload = {'chat_id': chat_id, 'name': name}
if icon_color:
payload['icon_color'] = icon_color
if icon_custom_emoji_id:
payload['icon_custom_emoji_id'] = icon_custom_emoji_id
return await _process_request(token, method_url, params=payload)
async def edit_forum_topic(token, chat_id, message_thread_id, name=None, icon_custom_emoji_id=None):
method_url = r'editForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
if name is not None:
payload['name'] = name
if icon_custom_emoji_id is not None:
payload['icon_custom_emoji_id'] = icon_custom_emoji_id
return await _process_request(token, method_url, params=payload)
async def close_forum_topic(token, chat_id, message_thread_id):
method_url = r'closeForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return await _process_request(token, method_url, params=payload)
async def reopen_forum_topic(token, chat_id, message_thread_id):
method_url = r'reopenForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return await _process_request(token, method_url, params=payload)
async def delete_forum_topic(token, chat_id, message_thread_id):
method_url = r'deleteForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return await _process_request(token, method_url, params=payload)
async def unpin_all_forum_topic_messages(token, chat_id, message_thread_id):
method_url = r'unpinAllForumTopicMessages'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return await _process_request(token, method_url, params=payload)
async def get_forum_topic_icon_stickers(token):
method_url = r'getForumTopicIconStickers'
return await _process_request(token, method_url)
async def edit_general_forum_topic(token, chat_id, name):
method_url = r'editGeneralForumTopic'
payload = {'chat_id': chat_id, 'name': name}
return await _process_request(token, method_url, params=payload)
async def close_general_forum_topic(token, chat_id):
method_url = r'closeGeneralForumTopic'
payload = {'chat_id': chat_id}
return await _process_request(token, method_url, params=payload)
async def reopen_general_forum_topic(token, chat_id):
method_url = r'reopenGeneralForumTopic'
payload = {'chat_id': chat_id}
return await _process_request(token, method_url, params=payload)
async def hide_general_forum_topic(token, chat_id):
method_url = r'hideGeneralForumTopic'
payload = {'chat_id': chat_id}
return await _process_request(token, method_url, params=payload)
async def unhide_general_forum_topic(token, chat_id):
method_url = r'unhideGeneralForumTopic'
payload = {'chat_id': chat_id}
return await _process_request(token, method_url, params=payload)
async def _convert_list_json_serializable(results):
@ -1789,10 +1974,10 @@ class ApiHTTPException(ApiException):
This class represents an Exception thrown when a call to the
Telegram API server returns HTTP code that is not 200.
"""
def __init__(self, function_name, result):
def __init__(self, function_name, result: aiohttp.ClientResponse):
super(ApiHTTPException, self).__init__(
"The server returned HTTP {0} {1}. Response body:\n[{2}]" \
.format(result.status_code, result.reason, result),
.format(result.status, result.reason, result.request_info),
function_name,
result)

View File

@ -28,7 +28,7 @@ class StatePickleStorage(StateStorageBase):
"""
Create directory .save-handlers.
"""
dirs = self.file_path.rsplit('/', maxsplit=1)[0]
dirs, filename = os.path.split(self.file_path)
os.makedirs(dirs, exist_ok=True)
if not os.path.isfile(self.file_path):
with open(self.file_path,'wb') as file:

View File

@ -1,12 +1,16 @@
from telebot.asyncio_storage.base_storage import StateStorageBase, StateContext
import json
redis_installed = True
is_actual_aioredis = False
try:
import aioredis
except:
redis_installed = False
is_actual_aioredis = True
except ImportError:
try:
from redis import asyncio as aioredis
except ImportError:
redis_installed = False
class StateRedisStorage(StateStorageBase):
@ -20,10 +24,10 @@ class StateRedisStorage(StateStorageBase):
if not redis_installed:
raise ImportError('AioRedis is not installed. Install it via "pip install aioredis"')
aioredis_version = tuple(map(int, aioredis.__version__.split(".")[0]))
if aioredis_version < (2,):
raise ImportError('Invalid aioredis version. Aioredis version should be >= 2.0.0')
if is_actual_aioredis:
aioredis_version = tuple(map(int, aioredis.__version__.split(".")[0]))
if aioredis_version < (2,):
raise ImportError('Invalid aioredis version. Aioredis version should be >= 2.0.0')
self.redis = aioredis.Redis(host=host, port=port, db=db, password=password)
self.prefix = prefix
@ -167,6 +171,6 @@ class StateRedisStorage(StateStorageBase):
user_id = str(user_id)
if response:
if user_id in response:
response[user_id]['data'] = dict(data, **response[user_id]['data'])
response[user_id]['data'] = data
await self.set_record(chat_id, response)
return True

View File

@ -428,7 +428,7 @@ class StateFilter(AdvancedCustomFilter):
text = text.name
if message.chat.type in ['group', 'supergroup']:
group_state = self.bot.current_states.get_state(user_id, chat_id)
group_state = self.bot.current_states.get_state(chat_id, user_id)
if group_state == text:
return True
elif type(text) is list and group_state in text:
@ -436,7 +436,7 @@ class StateFilter(AdvancedCustomFilter):
else:
user_state = self.bot.current_states.get_state(user_id, chat_id)
user_state = self.bot.current_states.get_state(chat_id, user_id)
if user_state == text:
return True
elif type(text) is list and user_state in text:

View File

@ -25,11 +25,11 @@ from typing import Optional
class AsyncWebhookListener:
def __init__(self, bot,
secret_token: str, host: Optional[str]="127.0.0.1",
secret_token: str,
host: Optional[str]="127.0.0.1",
port: Optional[int]=443,
ssl_context: Optional[tuple]=None,
url_path: Optional[str]=None,
debug: Optional[bool]=False
) -> None:
"""
Aynchronous implementation of webhook listener
@ -55,9 +55,6 @@ class AsyncWebhookListener:
:param url_path: Webhook url path
:type url_path: str
:param debug: Debug mode
:type debug: bool
:raises ImportError: If FastAPI or uvicorn is not installed.
:raises ImportError: If Starlette version is too old.
@ -72,7 +69,6 @@ class AsyncWebhookListener:
self._host = host
self._ssl_context = ssl_context
self._url_path = url_path
self._debug = debug
self._prepare_endpoint_urls()
@ -119,7 +115,6 @@ class AsyncWebhookListener:
config = Config(app=self.app,
host=self._host,
port=self._port,
debug=self._debug,
ssl_certfile=self._ssl_context[0],
ssl_keyfile=self._ssl_context[1]
)

31
telebot/ext/reloader.py Normal file
View File

@ -0,0 +1,31 @@
from watchdog.events import FileSystemEventHandler
from watchdog.events import FileSystemEvent
import psutil
import os
import sys
import logging
logger = logging.getLogger('TeleBot')
class EventHandler(FileSystemEventHandler):
def on_any_event(self, event: FileSystemEvent):
logger.info('* Detected changes in: %s, reloading', (event.src_path))
restart_file()
def restart_file():
try:
p = psutil.Process(os.getpid())
for handler in p.open_files() + p.connections():
os.close(handler.fd)
except OSError:
pass
except Exception as e:
logger.error(e)
python = sys.executable
if os.name == 'nt':
os.execv(sys.executable, ['python'] + sys.argv)
else:
os.execl(python, python, *sys.argv)

View File

@ -1,6 +1,5 @@
"""
This file is used by TeleBot.run_webhooks() function.
Fastapi is required to run this script.
"""
@ -15,31 +14,27 @@ try:
except ImportError:
fastapi_installed = False
from telebot.types import Update
from typing import Optional
class SyncWebhookListener:
def __init__(self, bot,
secret_token: str, host: Optional[str]="127.0.0.1",
secret_token: str,
host: Optional[str]="127.0.0.1",
port: Optional[int]=443,
ssl_context: Optional[tuple]=None,
url_path: Optional[str]=None,
debug: Optional[bool]=False
) -> None:
"""
Aynchronous implementation of webhook listener
for asynchronous version of telebot.
Synchronous implementation of webhook listener
for synchronous version of telebot.
Not supposed to be used manually by user.
Use AsyncTeleBot.run_webhooks() instead.
Use TeleBot.run_webhooks() instead.
:param bot: AsyncTeleBot instance.
:type bot: telebot.async_telebot.AsyncTeleBot
:param bot: TeleBot instance.
:type bot: telebot.TeleBot
:param secret_token: Telegram secret token
:type secret_token: str
@ -56,9 +51,6 @@ class SyncWebhookListener:
:param url_path: Webhook url path
:type url_path: str
:param debug: Debug mode
:type debug: bool
:raises ImportError: If FastAPI or uvicorn is not installed.
:raises ImportError: If Starlette version is too old.
@ -73,11 +65,11 @@ class SyncWebhookListener:
self._host = host
self._ssl_context = ssl_context
self._url_path = url_path
self._debug = debug
self._prepare_endpoint_urls()
def _check_dependencies(self):
@staticmethod
def _check_dependencies():
if not fastapi_installed:
raise ImportError('Fastapi or uvicorn is not installed. Please install it via pip.')
@ -119,7 +111,6 @@ class SyncWebhookListener:
uvicorn.run(app=self.app,
host=self._host,
port=self._port,
debug=self._debug,
ssl_certfile=self._ssl_context[0],
ssl_keyfile=self._ssl_context[1]
)

View File

@ -61,8 +61,8 @@ def escape_markdown(content: str) -> str:
:rtype: :obj:`str`
"""
parse = re.sub(r"([_*\[\]()~`>\#\+\-=|\.!])", r"\\\1", content)
reparse = re.sub(r"\\\\([_*\[\]()~`>\#\+\-=|\.!])", r"\1", parse)
parse = re.sub(r"([_*\[\]()~`>\#\+\-=|\.!\{\}\\])", r"\\\1", content)
reparse = re.sub(r"\\\\([_*\[\]()~`>\#\+\-=|\.!\{\}\\])", r"\1", parse)
return reparse
@ -323,4 +323,4 @@ def hide_link(url: str) -> str:
:return: The hidden url.
:rtype: :obj:`str`
"""
return f'<a href="{url}">&#8288;</a>'
return f'<a href="{url}">&#8288;</a>'

View File

@ -174,7 +174,6 @@ class State:
def __str__(self) -> str:
return self.name
class StatesGroup:
"""
@ -186,16 +185,20 @@ class StatesGroup:
my_state = State() # returns my_state:State string.
"""
def __init_subclass__(cls) -> None:
state_list = []
for name, value in cls.__dict__.items():
if not name.startswith('__') and not callable(value) and isinstance(value, State):
# change value of that variable
value.name = ':'.join((cls.__name__, name))
value.group = cls
state_list.append(value)
cls._state_list = state_list
@property
def state_list(self):
return self._state_list
class BaseMiddleware:
"""
Base class for middleware.
@ -253,10 +256,10 @@ class SkipHandler:
Update will go to post_process,
but will skip execution of handler.
"""
def __init__(self) -> None:
pass
class CancelUpdate:
"""
Class for canceling updates.
@ -265,6 +268,28 @@ class CancelUpdate:
Update will skip handler and execution
of post_process in middlewares.
"""
def __init__(self) -> None:
pass
pass
class ContinueHandling:
"""
Class for continue updates in handlers.
Just return instance of this class
in handlers to continue process.
.. code-block:: python3
:caption: Example of using ContinueHandling
@bot.message_handler(commands=['start'])
def start(message):
bot.send_message(message.chat.id, 'Hello World!')
return ContinueHandling()
@bot.message_handler(commands=['start'])
def start2(message):
bot.send_message(message.chat.id, 'Hello World2!')
"""
def __init__(self) -> None:
pass

84
telebot/service_utils.py Normal file
View File

@ -0,0 +1,84 @@
import random
import string
from io import BytesIO
try:
# noinspection PyPackageRequirements
from PIL import Image
pil_imported = True
except ImportError:
pil_imported = False
def is_string(var) -> bool:
"""
Returns True if the given object is a string.
"""
return isinstance(var, str)
def is_dict(var) -> bool:
"""
Returns True if the given object is a dictionary.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a dictionary.
:rtype: :obj:`bool`
"""
return isinstance(var, dict)
def is_bytes(var) -> bool:
"""
Returns True if the given object is a bytes object.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a bytes object.
:rtype: :obj:`bool`
"""
return isinstance(var, bytes)
def is_pil_image(var) -> bool:
"""
Returns True if the given object is a PIL.Image.Image object.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a PIL.Image.Image object.
:rtype: :obj:`bool`
"""
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 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() -> str:
"""
Generates a random token consisting of letters and digits, 16 characters long.
:return: a random token
:rtype: :obj:`str`
"""
return ''.join(random.sample(string.ascii_letters, 16))

View File

@ -41,7 +41,10 @@ class StateStorageBase:
def get_state(self, chat_id, user_id):
raise NotImplementedError
def get_interactive_data(self, chat_id, user_id):
raise NotImplementedError
def save(self, chat_id, user_id, data):
raise NotImplementedError

View File

@ -3,6 +3,7 @@ from telebot.storage.base_storage import StateStorageBase, StateContext
class StateMemoryStorage(StateStorageBase):
def __init__(self) -> None:
super().__init__()
self.data = {}
#
# {chat_id: {user_id: {'state': None, 'data': {}}, ...}, ...}

View File

@ -5,8 +5,8 @@ import pickle
class StatePickleStorage(StateStorageBase):
# noinspection PyMissingConstructor
def __init__(self, file_path="./.state-save/states.pkl") -> None:
super().__init__()
self.file_path = file_path
self.create_dir()
self.data = self.read()
@ -34,7 +34,7 @@ class StatePickleStorage(StateStorageBase):
"""
Create directory .save-handlers.
"""
dirs = self.file_path.rsplit('/', maxsplit=1)[0]
dirs, filename = os.path.split(self.file_path)
os.makedirs(dirs, exist_ok=True)
if not os.path.isfile(self.file_path):
with open(self.file_path,'wb') as file:

View File

@ -16,6 +16,7 @@ class StateRedisStorage(StateStorageBase):
TeleBot(storage=StateRedisStorage())
"""
def __init__(self, host='localhost', port=6379, db=0, password=None, prefix='telebot_'):
super().__init__()
self.redis = ConnectionPool(host=host, port=port, db=db, password=password)
#self.con = Redis(connection_pool=self.redis) -> use this when necessary
#
@ -173,7 +174,7 @@ class StateRedisStorage(StateStorageBase):
user_id = str(user_id)
if response:
if user_id in response:
response[user_id]['data'] = dict(data, **response[user_id]['data'])
response[user_id]['data'] = data
self.set_record(chat_id, response)
return True

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,5 @@
# -*- coding: utf-8 -*-
import random
import re
import string
import threading
import traceback
from typing import Any, Callable, List, Dict, Optional, Union
@ -14,21 +12,13 @@ import queue as Queue
import logging
from telebot import types
from telebot.service_utils import is_pil_image, is_dict, is_string, is_bytes, chunks, generate_random_token, pil_image_to_file
try:
import ujson as json
except ImportError:
import json
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')
@ -37,23 +27,25 @@ thread_local = threading.local()
#: Contains all media content types.
content_type_media = [
'text', 'audio', 'animation', 'document', 'photo', 'sticker', 'video', 'video_note', 'voice', 'contact', 'dice', 'poll',
'venue', 'location'
'text', 'audio', 'document', 'animation', 'game', 'photo', 'sticker', 'video', 'video_note', 'voice', 'contact',
'location', 'venue', 'dice', 'invoice', 'successful_payment', 'connected_website', 'poll', 'passport_data',
'web_app_data',
]
#: Contains all service content types such as `User joined the group`.
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', 'video_chat_scheduled', 'video_chat_started', 'video_chat_ended',
'video_chat_participants_invited', 'message_auto_delete_timer_changed'
'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', 'video_chat_scheduled', 'video_chat_started',
'video_chat_ended', 'video_chat_participants_invited', 'message_auto_delete_timer_changed', 'forum_topic_created',
'forum_topic_closed', 'forum_topic_reopened', 'user_shared', 'chat_shared',
]
#: All update types, should be used for allowed_updates parameter in polling.
update_types = [
"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"
"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",
]
@ -127,6 +119,7 @@ class ThreadPool:
"""
:meta private:
"""
def __init__(self, telebot, num_threads=2):
self.telebot = telebot
self.tasks = Queue.Queue()
@ -160,13 +153,15 @@ class ThreadPool:
for worker in self.workers:
worker.stop()
for worker in self.workers:
worker.join()
if worker != threading.current_thread():
worker.join()
class AsyncTask:
"""
:meta private:
"""
def __init__(self, target, *args, **kwargs):
self.target = target
self.args = args
@ -196,7 +191,8 @@ class CustomRequestResponse():
"""
:meta private:
"""
def __init__(self, json_text, status_code = 200, reason = ""):
def __init__(self, json_text, status_code=200, reason=""):
self.status_code = status_code
self.text = json_text
self.reason = reason
@ -209,6 +205,7 @@ def async_dec():
"""
:meta private:
"""
def decorator(fn):
def wrapper(*args, **kwargs):
return AsyncTask(fn, *args, **kwargs)
@ -218,63 +215,6 @@ def async_dec():
return decorator
def is_string(var) -> bool:
"""
Returns True if the given object is a string.
"""
return isinstance(var, str)
def is_dict(var) -> bool:
"""
Returns True if the given object is a dictionary.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a dictionary.
:rtype: :obj:`bool`
"""
return isinstance(var, dict)
def is_bytes(var) -> bool:
"""
Returns True if the given object is a bytes object.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a bytes object.
:rtype: :obj:`bool`
"""
return isinstance(var, bytes)
def is_pil_image(var) -> bool:
"""
Returns True if the given object is a PIL.Image.Image object.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a PIL.Image.Image object.
:rtype: :obj:`bool`
"""
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:
r"""
Checks if `text` is a command. Telegram chat commands start with the '/' character.
@ -333,6 +273,39 @@ def extract_arguments(text: str) -> str or None:
result = regexp.match(text)
return result.group(2) if is_command(text) else None
def extract_entity(text: str, e: types.MessageEntity) -> str:
"""
Returns the content of the entity.
:param text: The text of the message the entity belongs to
:type text: :obj:`str`
:param e: The entity to extract
:type e: :obj:`MessageEntity`
:return: The content of the entity
:rtype: :obj:`str`
"""
offset = 0
start = 0
encoded_text = text.encode()
end = len(encoded_text)
i = 0
for byte in encoded_text:
if (byte & 0xc0) != 0x80:
if offset == e.offset:
start = i
elif offset - e.offset == e.length:
end = i
break
if byte >= 0xf0:
offset += 2
else:
offset += 1
i += 1
return encoded_text[start:end].decode()
def split_string(text: str, chars_per_string: int) -> List[str]:
"""
@ -351,7 +324,7 @@ def split_string(text: str, chars_per_string: int) -> List[str]:
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]:
def smart_split(text: str, chars_per_string: int = MAX_MESSAGE_LENGTH) -> List[str]:
r"""
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.
@ -381,9 +354,12 @@ def smart_split(text: str, chars_per_string: int=MAX_MESSAGE_LENGTH) -> List[str
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(" ")
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):]
@ -397,11 +373,14 @@ def escape(text: str) -> str:
:return: the escaped text
"""
chars = {"&": "&amp;", "<": "&lt;", ">": "&gt;"}
for old, new in chars.items(): text = text.replace(old, new)
if text is None:
return None
for old, new in chars.items():
text = text.replace(old, new)
return text
def user_link(user: types.User, include_id: bool=False) -> str:
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'!
@ -428,10 +407,10 @@ def user_link(user: types.User, include_id: bool=False) -> str:
"""
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 ""))
+ (f" (<pre>{user.id}</pre>)" if include_id else ""))
def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int=2) -> types.InlineKeyboardMarkup:
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(...)'
@ -441,11 +420,13 @@ def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int=2) -> types.I
.. code-block:: python3
:caption: Using quick_markup:
quick_markup({
from telebot.util import quick_markup
markup = quick_markup({
'Twitter': {'url': 'https://twitter.com'},
'Facebook': {'url': 'https://facebook.com'},
'Back': {'callback_data': 'whatever'}
}, row_width=2):
}, 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
@ -464,7 +445,7 @@ def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int=2) -> types.I
:param values: a dict containing all buttons to create in this format: {text: kwargs} {str:}
:type values: :obj:`dict`
:param row_width: int row width
:param row_width: number of :class:`telebot.types.InlineKeyboardButton` objects on each row
:type row_width: :obj:`int`
:return: InlineKeyboardMarkup
@ -546,24 +527,7 @@ def per_thread(key, construct_value, reset=False):
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() -> str:
"""
Generates a random token consisting of letters and digits, 16 characters long.
:return: a random token
:rtype: :obj:`str`
"""
return ''.join(random.sample(string.ascii_letters, 16))
def deprecated(warn: bool=True, alternative: Optional[Callable]=None, deprecation_text=None):
def deprecated(warn: bool = True, alternative: Optional[Callable] = None, deprecation_text=None):
"""
Use this decorator to mark functions as deprecated.
When the function is used, an info (or warning if `warn` is True) is logged.
@ -581,6 +545,7 @@ def deprecated(warn: bool=True, alternative: Optional[Callable]=None, deprecatio
:return: The decorated function
"""
def decorator(function):
def wrapper(*args, **kwargs):
info = f"`{function.__name__}` is deprecated."
@ -593,7 +558,9 @@ def deprecated(warn: bool=True, alternative: Optional[Callable]=None, deprecatio
else:
logger.warning(info)
return function(*args, **kwargs)
return wrapper
return decorator
@ -623,7 +590,7 @@ def webhook_google_functions(bot, request):
return 'Bot ON'
def antiflood(function: Callable, *args, **kwargs):
def antiflood(function: Callable, *args, number_retries=5, **kwargs):
"""
Use this function inside loops in order to avoid getting TooManyRequests error.
Example:
@ -637,6 +604,9 @@ def antiflood(function: Callable, *args, **kwargs):
:param function: The function to call
:type function: :obj:`Callable`
:param number_retries: Number of retries to send
:type function: :obj:int
:param args: The arguments to pass to the function
:type args: :obj:`tuple`
@ -647,17 +617,19 @@ def antiflood(function: Callable, *args, **kwargs):
"""
from telebot.apihelper import ApiTelegramException
from time import sleep
msg = None
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
for _ in range(number_retries - 1):
try:
return function(*args, **kwargs)
except ApiTelegramException as ex:
if ex.error_code == 429:
sleep(ex.result_json['parameters']['retry_after'])
else:
raise
else:
return function(*args, **kwargs)
def parse_web_app_data(token: str, raw_init_data: str):
"""
Parses web app data.
@ -710,4 +682,16 @@ def validate_web_app_data(token: str, raw_init_data: str):
return hmac.new(secret_key.digest(), data_check_string.encode(), sha256).hexdigest() == init_data_hash
__all__ = (
"content_type_media", "content_type_service", "update_types",
"WorkerThread", "AsyncTask", "CustomRequestResponse",
"async_dec", "deprecated",
"is_bytes", "is_string", "is_dict", "is_pil_image",
"chunks", "generate_random_token", "pil_image_to_file",
"is_command", "extract_command", "extract_arguments",
"split_string", "smart_split", "escape", "user_link", "quick_markup",
"antiflood", "parse_web_app_data", "validate_web_app_data",
"or_set", "or_clear", "orify", "OrEvent", "per_thread",
"webhook_google_functions"
)

View File

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

View File

@ -470,6 +470,53 @@ class TestTeleBot:
for i in range(0,200):
util.antiflood(tb.send_message, CHAT_ID, text)
assert i == 199
def test_extract_entity(self):
entities_map = {"https://core.telegram.org/api/entities": "https://core.telegram.org/api/entities",
"https://github.com/eternnoir/pyTelegramBotAPI": "https://github.com/eternnoir/pyTelegramBotAPI",
"*粗 bold text体*": "粗 bold text体",
"_斜体 italic text_": "斜体 italic text",
"[谷歌](http://www.google.com/)": "谷歌",
'`std::cout<<"test"<<std::endl;`': 'std::cout<<"test"<<std::endl;',
'''```rust
let number = loop {
println!("Pick a pattern from 0-2:");
stdin.read_line(&mut option).unwrap();
match option.lines().next().unwrap().parse::<usize>() {
Ok(number @ 0..=2) => break number,
_ => {
println!("invalid input!");
option = String::new();
continue;
}
};
};```''': '''let number = loop {
println!("Pick a pattern from 0-2:");
stdin.read_line(&mut option).unwrap();
match option.lines().next().unwrap().parse::<usize>() {
Ok(number @ 0..=2) => break number,
_ => {
println!("invalid input!");
option = String::new();
continue;
}
};
};''',
"@username": "@username",
"#hashtag索引标签": "#hashtag索引标签",
"do-not-reply@telegram.org": "do-not-reply@telegram.org",
"+12125550123": "+12125550123"}
entites = list(entities_map.keys())
contents = list(entities_map.values())
contents.sort()
text = '\n'.join(entites)
bot = telebot.TeleBot(TOKEN)
message = bot.send_message(CHAT_ID, text, parse_mode="Markdown")
extracted_contents = [util.extract_entity(
message.text, e) for e in message.entities]
extracted_contents.sort()
assert contents == extracted_contents
@staticmethod
def create_text_message(text):

View File

@ -67,9 +67,9 @@ def test_json_GroupChat():
def test_json_Document():
json_string = r'{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AgADJQEAAqfhOEY","file_size":446}'
json_string = r'{"file_name":"Text File","thumbnail":{},"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.thumbnail is None
assert doc.file_name == 'Text File'
@ -83,23 +83,23 @@ def test_json_Message_Audio():
def test_json_Message_Sticker():
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": {"type": "regular", "width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "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}}'
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": {"type": "regular", "width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "thumbnail": {"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
assert msg.sticker.thumbnail.height == 60
assert msg.content_type == 'sticker'
def test_json_Message_Sticker_without_thumb():
def test_json_Message_Sticker_without_thumbnail():
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": {"type": "regular", "width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "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 is None
assert msg.sticker.thumbnail 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","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}}'
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","thumbnail":{},"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'
@ -113,11 +113,11 @@ def test_json_Message_Photo():
def test_json_Message_Video():
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}}'
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,"thumbnail":{"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
assert msg.video.thumb.width == 50
assert msg.video.thumbnail.width == 50
assert msg.content_type == 'video'
@ -271,5 +271,33 @@ def test_sent_web_app_message():
assert sent_web_app_message.inline_message_id == '29430'
def test_message_entity():
# TODO: Add support for nesting entities
sample_string_1 = r'{"update_id":934522126,"message":{"message_id":1374510,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682177590,"text":"b b b","entities":[{"offset":0,"length":2,"type":"bold"},{"offset":0,"length":1,"type":"italic"},{"offset":2,"length":2,"type":"bold"},{"offset":2,"length":1,"type":"italic"},{"offset":4,"length":1,"type":"bold"},{"offset":4,"length":1,"type":"italic"}]}}'
update = types.Update.de_json(sample_string_1)
message: types.Message = update.message
assert message.html_text == "<i><b>b </b></i><i><b>b </b></i><i><b>b</b></i>"
sample_string_2 = r'{"update_id":934522166,"message":{"message_id":1374526,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682179716,"text":"b b b","entities":[{"offset":0,"length":1,"type":"bold"},{"offset":2,"length":1,"type":"bold"},{"offset":4,"length":1,"type":"italic"}]}}'
message_2 = types.Update.de_json(sample_string_2).message
assert message_2.html_text == "<b>b</b> <b>b</b> <i>b</i>"
sample_string_3 = r'{"update_id":934522172,"message":{"message_id":1374530,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682179968,"text":"This is a bold text with a nested italic and bold text.","entities":[{"offset":10,"length":4,"type":"bold"},{"offset":27,"length":7,"type":"italic"},{"offset":34,"length":15,"type":"bold"},{"offset":34,"length":15,"type":"italic"}]}}'
message_3 = types.Update.de_json(sample_string_3).message
assert message_3.html_text == "This is a <b>bold</b> text with a <i>nested </i><i><b>italic and bold</b></i> text."
sample_string_4 = r'{"update_id":934522437,"message":{"message_id":1374619,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682189507,"forward_from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"forward_date":1682189124,"text":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa😋😋","entities":[{"offset":0,"length":76,"type":"bold"},{"offset":0,"length":76,"type":"italic"},{"offset":0,"length":76,"type":"underline"},{"offset":0,"length":76,"type":"strikethrough"},{"offset":76,"length":2,"type":"custom_emoji","custom_emoji_id":"5456188142006575553"},{"offset":78,"length":2,"type":"custom_emoji","custom_emoji_id":"5456188142006575553"}]}}'
message_4 = types.Update.de_json(sample_string_4).message
assert message_4.html_text == '<s><u><i><b>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</b></i></u></s><tg-emoji emoji-id="5456188142006575553">😋</tg-emoji><tg-emoji emoji-id="5456188142006575553">😋</tg-emoji>'