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

Compare commits

..

82 Commits
1.4.1 ... 2.0.5

Author SHA1 Message Date
769bb55bbe Update test. 2016-05-03 21:05:11 +08:00
655940dcf8 Update version. 2016-05-03 21:02:46 +08:00
3b52e5c49b ReplyKeyboardMarkup support string. 2016-05-03 21:02:46 +08:00
700b869555 Merge pull request #154 from tp6vup54/master
Fix the bug that the return of request.get_data() is not string.
2016-05-02 21:12:29 +08:00
5906d632d6 Fix the bug that the return of request.get_data() is not string. 2016-05-02 11:07:23 +00:00
bd513cd343 Merge branch 'master' of github.com:eternnoir/pyTelegramBotAPI 2016-05-01 00:25:28 +08:00
0cb99b42e4 Update version. 2016-05-01 00:25:10 +08:00
dc1869167d Fix #153 2016-05-01 00:24:54 +08:00
ef22fafa7e Merge pull request #146 from rmed/fix-regexp
Added missing import for extract_arguments()
2016-04-26 23:14:38 +08:00
94d1b3f7a8 Added missing import for extract_arguments() 2016-04-26 11:16:49 +02:00
ef68bed01f Version update. 2016-04-25 23:55:03 +08:00
0eb21aa673 Fix #138. 2016-04-25 23:54:30 +08:00
e6105d851c Merge pull request #142 from Pitasi/master
Fixed new/left_chat_member content types
2016-04-25 23:32:44 +08:00
7ec33d43b3 Fixed supper for new/left_chat_member content types 2016-04-24 17:53:13 +02:00
0a856f4e83 Fix test case. 2016-04-23 09:29:48 +08:00
bbe53b5e17 Fix #136 and Update version. 2016-04-23 01:24:50 +08:00
84257b6ba9 Fix typo. 2016-04-23 01:21:45 +08:00
5b234920c7 Version Update.
Change log:
- duplicated code remove.
2016-04-19 08:19:20 +08:00
16d4c64b00 Remove duplicated method. 2016-04-19 08:13:37 +08:00
4fb85e25f6 Update rst readme. 2016-04-18 13:39:00 +08:00
0ae20e1a49 Update version. 2016-04-18 13:37:24 +08:00
e913635755 fix next_offset is empty will not set bug. 2016-04-17 23:28:47 +08:00
225cbf2c61 Update switch_inline_query is empty not set bug. 2016-04-17 23:21:11 +08:00
ae63b8029f Merge pull request #134 from Kondra007/patch-5
Fixed typo in types.py
2016-04-17 22:58:37 +08:00
e47790ded8 Fixed typo in types.py
"switch_inline_quer" -> "switch_inline_query"
2016-04-17 17:54:01 +03:00
d0666071d8 Fix edit inlinemessage will return bool not Message object. 2016-04-17 10:24:37 +08:00
eb8e87fdec Merge pull request #133 from Kondra007/patch-4
Fix Readme.md
2016-04-17 10:24:15 +08:00
1c98e1108c Fix Readme.md
Fixed Readme so "Bot 2.0" link leads to proper paragraph
2016-04-16 22:24:48 +03:00
8a0bf8ca7e Update readme. 2016-04-16 15:08:01 +08:00
7490f63f25 Add send_contact 2016-04-16 15:07:52 +08:00
22ab50989e Add answer_callback_query. 2016-04-16 14:53:41 +08:00
1e320a5b0d Add callback query handler. 2016-04-16 14:18:19 +08:00
96e06c248b Merge pull request #131 from Kondra007/patch-4
Fixed typo in InlineQueryResultAudio
2016-04-16 11:22:33 +08:00
ae92d1998e Fixed typo in InlineQueryResultArticle 2016-04-15 21:04:08 +03:00
d87e0821c9 Fix type test. 2016-04-14 17:45:57 +08:00
ee52241cc2 Update inline example. 2016-04-14 17:43:45 +08:00
a6d35fd1de Add all inquery types. 2016-04-14 17:09:12 +08:00
016819cd44 Add inline query classes. 2016-04-14 16:57:23 +08:00
036441b8f6 Add new inline type. 2016-04-14 15:50:55 +08:00
228683aeda Add new param for anser inline query. 2016-04-14 15:32:08 +08:00
4fe4061a0f All Updating messages methods done. 2016-04-14 15:17:53 +08:00
f873658aac Fix edit message error. 2016-04-14 15:06:46 +08:00
13327c371a Add editMessageText. 2016-04-14 15:03:07 +08:00
4dc7af71a0 Add bot2.0 new methods. 2016-04-14 14:48:26 +08:00
209764a5d7 Add connect timeout. Fix #108 2016-04-14 14:34:37 +08:00
c1247249c7 Add send venu method. 2016-04-14 13:55:28 +08:00
a6b0e9598c Add inline keyboard test. 2016-04-14 13:35:18 +08:00
7958264d64 Add bot 2.0 markup. 2016-04-14 12:01:17 +08:00
74c3a3545d Update type message to bot2.0 define. 2016-04-14 11:15:58 +08:00
7b007dab99 Add venue to message type. 2016-04-14 11:02:19 +08:00
8316a57845 Add type Venue. 2016-04-14 11:00:33 +08:00
2eb914d329 Add message entity to message. 2016-04-14 10:57:18 +08:00
2449a3ea64 Add MessageEntity. 2016-04-14 10:51:05 +08:00
a2d91808ef Remove pytest. 2016-04-09 10:37:34 +08:00
23dd31752b Update README.md 2016-04-04 10:51:27 +08:00
7770fcbb33 Update README.md 2016-03-29 11:34:37 +08:00
c64fdf149e Merge pull request #121 from DrBomb/patch-1
extract_argument
2016-03-18 15:09:21 +08:00
17184697ea Update util.py
Another typo
2016-03-17 22:17:06 -04:30
78d86752fb Update util.py
Typo
2016-03-17 00:51:02 -04:30
7669781737 Update util.py
Added a regexp method that returns all the text after the command.
2016-03-17 00:48:08 -04:30
ddc1a4d66f Version Update.
Change log:
- Add disable_notification parameter.
- Added setters for message/inline/chosen-inline handlers.
2016-02-27 11:47:01 +08:00
3d9e012c40 Merge pull request #120 from eternnoir/feature-disable_notification
Feature disable notification
2016-02-27 11:45:23 +08:00
9b9c0287ec Add test case. 2016-02-27 11:36:53 +08:00
292191038f Add disable_notification 2016-02-27 11:17:35 +08:00
f0e157213c Merge pull request #119 from Kondra007/patch-4
Update README.md
2016-02-26 20:45:54 +08:00
18330275bd Corrected author of Proxy Bot 2016-02-26 15:34:14 +03:00
d173681a7c Update README.md 2016-02-25 20:49:45 +08:00
0830f2a0f9 Update README.md 2016-02-23 21:16:35 +08:00
45d6f8980c Merge pull request #117 from Dejust/add-handler-setters
Added setters for message/inline/chosen-inline handlers.
2016-02-21 10:56:22 +08:00
28417d18af Added ability to set message handler, inline handler, chosen inline handler with method calling 2016-02-20 17:51:14 +05:00
e0ae119512 Merge pull request #116 from idlesign/patch-1
answer_inline_query() made POST
2016-02-15 16:19:55 +08:00
e851f37712 answer_inline_query made POST
The default GET produces `414 Request-URI Too Large` response.
2016-02-14 00:08:37 +05:00
40cf8d6903 Update README.md 2016-02-14 02:00:00 +08:00
e507463741 Update README.md 2016-02-14 01:59:31 +08:00
3a055734f9 Update README.md 2016-02-14 01:52:46 +08:00
16ec573c9e Add more example. 2016-02-11 21:42:07 +08:00
2cd19a1a39 Merge pull request #113 from ratijas/master
__retrieve_updates split into process_new_updates
2016-02-08 23:09:15 +08:00
5f9cf881e6 __retrieve_updates split into process_new_updates 2016-02-07 23:45:54 +08:00
baacafe3c0 Update examples. 2016-02-01 22:50:47 +08:00
734767177d Merge pull request #110 from Kondra007/patch-4
Updated README
2016-01-25 09:50:18 +08:00
1e7f71029c Updated README
Added "supergroup" to message.chat examples.  
via https://core.telegram.org/bots/api-changelog#november-2015
2016-01-24 20:51:52 +03:00
02c22c990b Add chosen_inline_handler doc. 2016-01-19 13:56:44 +08:00
11 changed files with 1542 additions and 240 deletions

View File

@ -15,6 +15,7 @@
* [Methods](#methods)
* [General use of the API](#general-use-of-the-api)
* [Message handlers](#message-handlers)
* [Callback Query handlers](#message-handlers)
* [TeleBot](#telebot)
* [Reply markup](#reply-markup)
* [Inline Mode](#inline-mode)
@ -26,6 +27,7 @@
* [Using web hooks](#using-web-hooks)
* [Logging](#logging)
* [F.A.Q.](#faq)
* [Bot 2.0](#bot-20)
* [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)
* [The Telegram Chat Group](#the-telegram-chat-group)
* [More examples](#more-examples)
@ -153,6 +155,7 @@ TeleBot supports the following filters:
|func|a function (lambda or function reference)|`True` if the lambda or function reference returns `True`
Here are some examples of using the filters and message handlers:
```python
import telebot
bot = telebot.TeleBot("TOKEN")
@ -193,6 +196,17 @@ def send_something(message):
pass
```
**Important: all handlers are tested in the order in which they were declared**
#### Callback Query Handler
In bot2.0 update. You can get `callback_query` in update object. In telebot use `callback_query_handler` to process callback_querys.
```python
@bot.callback_query_handler(func=lambda call: True)
def test_callback(call):
logger.info(call)
```
#### TeleBot
```python
import telebot
@ -292,13 +306,21 @@ from telebot import types
# row_width is used in combination with the add() function.
# It defines how many buttons are fit on each row before continuing on the next row.
markup = types.ReplyKeyboardMarkup(row_width=2)
markup.add('a', 'v', 'd')
itembtn1 = types.KeyboardButton('a')
itembtn2 = types.KeyboardButton('v')
itembtn3 = types.KeyboardButton('d')
markup.add(itembtn1, itembtn2, itembtn3)
tb.send_message(chat_id, "Choose one letter:", reply_markup=markup)
# or add strings one row at a time:
# or add KeyboardButton one row at a time:
markup = types.ReplyKeyboardMarkup()
markup.row('a', 'v')
markup.row('c', 'd', 'e')
itembtna = types.KeyboardButton('a')
itembtnv = types.KeyboardButton('v')
itembtnc = types.KeyboardButton('c')
itembtnd = types.KeyboardButton('d')
itembtne = types.KeyboardButton('e')
markup.row(itembtna, itembtnv)
markup.row(itembtnc, itembtnd, itembtne)
tb.send_message(chat_id, "Choose one letter:", reply_markup=markup)
```
The last example yields this result:
@ -327,7 +349,9 @@ ForceReply:
More information about [Inline mode](https://core.telegram.org/bots/inline).
#### inline_handler
Now, you can use inline_handler to get inline_query in telebot.
```python
@bot.inline_handler(lambda query: query.query == 'text')
@ -335,6 +359,20 @@ def query_text(inline_query):
# Query message is text
```
#### chosen_inline_handler
Use chosen_inline_handler to get chosen_inline_result in telebot. Don't forgot add the /setinlinefeedback
command for @Botfather.
More information : [collecting-feedback](https://core.telegram.org/bots/inline#collecting-feedback)
```python
@bot.chosen_inline_handler(func=lambda chosen_inline_result: True)
def test_chosen(chosen_inline_result):
# Process all chosen_inline_result.
```
#### answer_inline_query
```python
@ -422,16 +460,26 @@ telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console.
## F.A.Q.
### Bot 2.0
April 9,2016 Telegram release new bot 2.0 API, which has a drastic revision especially for the change of method's interface.If you want to update to the latest version, please make sure you've switched bot's code to bot 2.0 method interface.
[More information about pyTelegramBotAPI support bot2.0](https://github.com/eternnoir/pyTelegramBotAPI/issues/130)
### How can I distinguish a User and a GroupChat in message.chat?
Telegram Bot API support new type Chat for message.chat.
- Check the ```type``` attribute in ```Chat``` object:
-
```python
if message.chat.type == private:
# private chat message
if message.chat.type == group:
# group chat message
if message.chat.type == supergroup:
# supergroup chat message
if message.chat.type == channel:
# channel message
@ -454,4 +502,14 @@ Get help. Discuss. Chat.
## Bots using this API
* [SiteAlert bot](https://telegram.me/SiteAlert_bot) ([source](https://github.com/ilteoood/SiteAlert-Python)) by *ilteoood* - Monitors websites and sends a notification on changes
* [TelegramLoggingBot](https://github.com/aRandomStranger/TelegramLoggingBot) by *aRandomStranger*
* [Telegram LMGTFY_bot](https://github.com/GabrielRF/telegram-lmgtfy_bot) by *GabrielRF*
* [Telegram UrlProBot](https://github.com/GabrielRF/telegram-urlprobot) by *GabrielRF*
* [Telegram Proxy Bot](https://bitbucket.org/master_groosha/telegram-proxy-bot) by *Groosha* - A simple BITM (bot-in-the-middle) for Telegram acting as some kind of "proxy".
* [Telegram Proxy Bot](https://github.com/mrgigabyte/proxybot) by *mrgigabyte* - `Credits for the original version of this bot goes to` **Groosha** `, simply added certain features which I thought were needed`.
* [RadRetroRobot](https://github.com/Tronikart/RadRetroRobot) by *Tronikart* - Multifunctional Telegram Bot RadRetroRobot.
* [League of Legends bot](https://telegram.me/League_of_Legends_bot) ([source](https://github.com/i32ropie/lol)) by *i32ropie*
* [NeoBot](https://github.com/neoranger/NeoBot) by *neoranger*
* [TagAlertBot](https://github.com/pitasi/TagAlertBot) by *pitasi*
Want to have your bot listed here? Send a Telegram message to @eternnoir or @pevdh.

View File

@ -13,11 +13,7 @@ pyTelegramBotAPI
A simple, but extensible Python implementation for the `Telegram Bot
API <https://core.telegram.org/bots/api>`__.
.. raw:: html
<p align="center">
|Build Status|
|Download Month| |Build Status| |Download Month|
- `Getting started. <#getting-started>`__
- `Writing your first bot <#writing-your-first-bot>`__
@ -31,8 +27,10 @@ API <https://core.telegram.org/bots/api>`__.
- `Methods <#methods>`__
- `General use of the API <#general-use-of-the-api>`__
- `Message handlers <#message-handlers>`__
- `Callback Query handlers <#message-handlers>`__
- `TeleBot <#telebot>`__
- `Reply markup <#reply-markup>`__
- `Inline Mode <#inline-mode>`__
- `Advanced use of the API <#advanced-use-of-the-api>`__
@ -47,6 +45,7 @@ API <https://core.telegram.org/bots/api>`__.
- `F.A.Q. <#faq>`__
- `Bot 2.0 <#bot-20>`__
- `How can I distinguish a User and a GroupChat in
message.chat? <#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat>`__
@ -55,7 +54,7 @@ API <https://core.telegram.org/bots/api>`__.
- `Bots using this API <#bots-using-this-api>`__
Getting started.
================
----------------
This API is tested with Python 2.6, Python 2.7, Python 3.4, Pypy and
Pypy 3. There are two ways to install the library:
@ -81,10 +80,10 @@ it has regular updates, do not forget to update it regularly by calling
``pip install pytelegrambotapi --upgrade``\ \*
Writing your first bot
======================
----------------------
Prerequisites
-------------
~~~~~~~~~~~~~
It is presumed that you [have obtained an API token with
@BotFather](https://core.telegram.org/bots#botfather). We will call this
@ -93,7 +92,7 @@ programming language and more importantly `the Telegram Bot
API <https://core.telegram.org/bots/api>`__.
A simple echo bot
-----------------
~~~~~~~~~~~~~~~~~
The TeleBot class (defined in \_\_init\_\_.py) encapsulates all API
calls in a single class. It provides functions such as ``send_xyz``
@ -175,10 +174,10 @@ To start the bot, simply open up a terminal and enter
('/start' and '/help') and arbitrary text messages.
General API Documentation
=========================
-------------------------
Types
-----
~~~~~
All types are defined in types.py. They are all completely in line with
the `Telegram API's definition of the
@ -190,15 +189,15 @@ Note that ``message.chat`` can be either an instance of ``User`` or
``GroupChat`` (see `How can I distinguish a User and a GroupChat in
message.chat? <#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat>`__).
The Message object also has a ``content_type``\ attribute, which defines
the type of the Message. ``content_type`` can be one of the following
strings: 'text', 'audio', 'document', 'photo', 'sticker', 'video',
'location', 'contact', 'new\_chat\_participant',
The Message object also has a ``content_types``\ attribute, which
defines the type of the Message. ``content_types`` can be one of the
following strings: 'text', 'audio', 'document', 'photo', 'sticker',
'video', 'voice', 'location', 'contact', 'new\_chat\_participant',
'left\_chat\_participant', 'new\_chat\_title', 'new\_chat\_photo',
'delete\_chat\_photo', 'group\_chat\_created'.
Methods
-------
~~~~~~~
All `API
methods <https://core.telegram.org/bots/api#available-methods>`__ are
@ -207,12 +206,12 @@ naming conventions. E.g. ``getMe`` is renamed to ``get_me`` and
``sendMessage`` to ``send_message``.
General use of the API
----------------------
~~~~~~~~~~~~~~~~~~~~~~
Outlined below are some general use cases of the API.
Message handlers
~~~~~~~~~~~~~~~~
^^^^^^^^^^^^^^^^
A message handler is a function that is decorated with the
``message_handler`` decorator of a TeleBot instance. Message handlers
@ -234,17 +233,122 @@ argument, which will be the message that the function must handle.
following manner: ``name=argument``. One handler may have multiple
filters. TeleBot supports the following filters:
+------------------+---------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| name | argument(s) | Condition |
+==================+=============================================+=================================================================================================================================================================================+
| content\_types | list of strings (default ``['text']``) | ``True`` if message.content\_type is in the list of strings. |
+------------------+---------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| regexp | a regular expression as a string | ``True`` if ``re.search(regexp_arg)`` returns ``True`` and ``message.content_type == 'text'`` (See `Python Regular Expressions <https://docs.python.org/2/library/re.html>`__ |
+------------------+---------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| commands | list of strings | ``True`` if ``message.content_type == 'text'`` and ``message.text`` starts with a command that is in the list of strings. |
+------------------+---------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| func | a function (lambda or function reference) | ``True`` if the lambda or function reference returns ``True`` |
+------------------+---------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+--------+------+------+
| name | argu | Cond |
| | ment | itio |
| | (s) | n |
+========+======+======+
| conten | list | ``Tr |
| t\_typ | of | ue`` |
| es | stri | if |
| | ngs | mess |
| | (def | age. |
| | ault | cont |
| | ``[' | ent\ |
| | text | _typ |
| | ']`` | e |
| | ) | is |
| | | in |
| | | the |
| | | list |
| | | of |
| | | stri |
| | | ngs. |
+--------+------+------+
| regexp | a | ``Tr |
| | regu | ue`` |
| | lar | if |
| | expr | ``re |
| | essi | .sea |
| | on | rch( |
| | as a | rege |
| | stri | xp_a |
| | ng | rg)` |
| | | ` |
| | | retu |
| | | rns |
| | | ``Tr |
| | | ue`` |
| | | and |
| | | ``me |
| | | ssag |
| | | e.co |
| | | nten |
| | | t_ty |
| | | pe = |
| | | = 't |
| | | ext' |
| | | `` |
| | | (See |
| | | `Pyt |
| | | hon |
| | | Regu |
| | | lar |
| | | Expr |
| | | essi |
| | | ons |
| | | <htt |
| | | ps:/ |
| | | /doc |
| | | s.py |
| | | thon |
| | | .org |
| | | /2/l |
| | | ibra |
| | | ry/r |
| | | e.ht |
| | | ml>` |
| | | __ |
+--------+------+------+
| comman | list | ``Tr |
| ds | of | ue`` |
| | stri | if |
| | ngs | ``me |
| | | ssag |
| | | e.co |
| | | nten |
| | | t_ty |
| | | pe = |
| | | = 't |
| | | ext' |
| | | `` |
| | | and |
| | | ``me |
| | | ssag |
| | | e.te |
| | | xt`` |
| | | star |
| | | ts |
| | | with |
| | | a |
| | | comm |
| | | and |
| | | that |
| | | is |
| | | in |
| | | the |
| | | list |
| | | of |
| | | stri |
| | | ngs. |
+--------+------+------+
| func | a | ``Tr |
| | func | ue`` |
| | tion | if |
| | (lam | the |
| | bda | lamb |
| | or | da |
| | func | or |
| | tion | func |
| | refe | tion |
| | renc | refe |
| | e) | renc |
| | | e |
| | | retu |
| | | rns |
| | | ``Tr |
| | | ue`` |
+--------+------+------+
Here are some examples of using the filters and message handlers:
@ -289,7 +393,22 @@ Here are some examples of using the filters and message handlers:
pass
**Important: all handlers are tested in the order in which they were
declared** #### TeleBot
declared**
Callback Query Handler
^^^^^^^^^^^^^^^^^^^^^^
In bot2.0 update. You can get ``callback_query`` in update object. In
telebot use ``callback_query_handler`` to process callback\_querys.
.. code:: python
@bot.callback_query_handler(func=lambda call: True)
def test_callback(call):
logger.info(call)
TeleBot
^^^^^^^
.. code:: python
@ -374,7 +493,7 @@ declared** #### TeleBot
file = requests.get('https://api.telegram.org/file/bot{0}/{1}'.format(API_TOKEN, file_info.file_path))
Reply markup
~~~~~~~~~~~~
^^^^^^^^^^^^
All ``send_xyz`` functions of TeleBot take an optional ``reply_markup``
argument. This argument must be an instance of ``ReplyKeyboardMarkup``,
@ -393,13 +512,21 @@ argument. This argument must be an instance of ``ReplyKeyboardMarkup``,
# row_width is used in combination with the add() function.
# It defines how many buttons are fit on each row before continuing on the next row.
markup = types.ReplyKeyboardMarkup(row_width=2)
markup.add('a', 'v', 'd')
itembtn1 = types.KeyboardButton('a')
itembtn2 = types.KeyboardButton('v')
itembtn3 = types.KeyboardButton('d')
markup.add(itembtn1, itembtn2, itembtn3)
tb.send_message(chat_id, "Choose one letter:", reply_markup=markup)
# or add strings one row at a time:
markup = types.ReplyKeyboardMarkup()
markup.row('a', 'v')
markup.row('c', 'd', 'e')
itembtna = types.KeyboardButton('a')
itembtnv = types.KeyboardButton('v')
itembtnc = types.KeyboardButton('c')
itembtnd = types.KeyboardButton('d')
itembtne = types.KeyboardButton('e')
markup.row(itembtna, itembtnv)
markup.row(itembtnc, itembtnd, itembtne)
tb.send_message(chat_id, "Choose one letter:", reply_markup=markup)
The last example yields this result:
@ -430,11 +557,58 @@ ForceReply:
ForceReply
Inline Mode
~~~~~~~~~~~
More information about `Inline
mode <https://core.telegram.org/bots/inline>`__.
inline\_handler
^^^^^^^^^^^^^^^
Now, you can use inline\_handler to get inline\_query in telebot.
.. code:: python
@bot.inline_handler(lambda query: query.query == 'text')
def query_text(inline_query):
# Query message is text
chosen\_inline\_handler
^^^^^^^^^^^^^^^^^^^^^^^
Use chosen\_inline\_handler to get chosen\_inline\_result in telebot.
Don't forgot add the /setinlinefeedback command for @Botfather.
More information :
`collecting-feedback <https://core.telegram.org/bots/inline#collecting-feedback>`__
.. code:: python
@bot.chosen_inline_handler(func=lambda chosen_inline_result: True)
def test_chosen(chosen_inline_result):
# Process all chosen_inline_result.
answer\_inline\_query
^^^^^^^^^^^^^^^^^^^^^
.. code:: python
@bot.inline_handler(lambda query: query.query == 'text')
def query_text(inline_query):
try:
r = types.InlineQueryResultArticle('1', 'Result', 'Result message.')
r2 = types.InlineQueryResultArticle('2', 'Result2', 'Result message2.')
bot.answer_inline_query(inline_query.id, [r, r2])
except Exception as e:
print(e)
Advanced use of the API
=======================
-----------------------
Asynchronous delivery of messages
---------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There exists an implementation of TeleBot which executes all
``send_xyz`` and the ``get_me`` functions asynchronously. This can speed
@ -469,7 +643,7 @@ calling wait(), the order in which messages are delivered might be
wrong.*
Sending large text messages
---------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sometimes you must send messages that exceed 5000 characters. The
Telegram API can not handle that many characters in one request, so we
@ -488,7 +662,7 @@ API:
tb.send_message(chat_id, text)
Controlling the amount of Threads used by TeleBot
-------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The TeleBot constructor takes the following optional arguments:
@ -501,7 +675,7 @@ The TeleBot constructor takes the following optional arguments:
False.
The listener mechanism
----------------------
~~~~~~~~~~~~~~~~~~~~~~
As an alternative to the message handlers, one can also register a
function as a listener to TeleBot. Example:
@ -517,7 +691,7 @@ function as a listener to TeleBot. Example:
bot.polling()
Using webhooks
--------------
~~~~~~~~~~~~~~
When using webhooks telegram sends one Update per call, for processing
it you should call process\_new\_messages([update.message]) when you
@ -527,7 +701,7 @@ There are some examples using webhooks in the
*examples/webhook\_examples* directory.
Logging
-------
~~~~~~~
You can use the Telebot module logger to log debug info about Telebot.
Use ``telebot.logger`` to get the logger of the TeleBot module. It is
@ -543,34 +717,48 @@ page <https://docs.python.org/2/library/logging.html>`__ for more info.
telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console.
F.A.Q.
======
------
Bot 2.0
~~~~~~~
April 9,2016 Telegram release new bot 2.0 API, which has a drastic
revision especially for the change of method's interface.If you want to
update to the latest version, please make sure you've switched bot's
code to bot 2.0 method interface.
`More information about pyTelegramBotAPI support
bot2.0 <https://github.com/eternnoir/pyTelegramBotAPI/issues/130>`__
How can I distinguish a User and a GroupChat in message.chat?
-------------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are two ways to do this:
Telegram Bot API support new type Chat for message.chat.
- Checking the instance of message.chat with ``isinstance``:
\`\`\`python def is\_user(chat): return isinstance(chat, types.User)
- Check the ``type`` attribute in ``Chat`` object:
- \`\`\`python if message.chat.type == “private”: # private chat
message
print is\_user(message.chat) # True or False
``- Checking whether the chat id is negative or positive. If the chat id is negative, the chat is a GroupChat, if it is positive, it is a User. Example:``\ python
def is\_user(chat): return chat.id > 0
if message.chat.type == “group”: # group chat message
print is\_user(message.chat) # True or False \`\`\`
if message.chat.type == “supergroup”: # supergroup chat message
if message.chat.type == “channel”: # channel message
\`\`\`
The Telegram Chat Group
=======================
-----------------------
Get help. Discuss. Chat.
Join the `pyTelegramBotAPI Telegram Chat
Group <https://telegram.me/joinchat/067e22c60035523fda8f6025ee87e30b>`__.
We now have a Telegram Channel as well! Keep yourself up to date with
API changes, and `join it <https://telegram.me/pytelegrambotapi>`__.
- Join the pyTelegramBotAPI Telegram Chat Group
- Messge to @eternnoir by telegram for Invitation.
- We now have a Telegram Channel as well! Keep yourself up to date with
API changes, and `join it <https://telegram.me/pytelegrambotapi>`__.
More examples
=============
-------------
- `Echo
Bot <https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/echo_bot.py>`__
@ -580,13 +768,40 @@ More examples
Example <https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/step_example.py>`__
Bots using this API
===================
-------------------
- `SiteAlert bot <https://telegram.me/SiteAlert_bot>`__
(`source <https://github.com/ilteoood/SiteAlert-Python>`__) by
*ilteoood* - Monitors websites and sends a notification on changes
Want to have your bot listed here? Send a Telegram message to
@eternnoir or @pevdh.
- `TelegramLoggingBot <https://github.com/aRandomStranger/TelegramLoggingBot>`__
by *aRandomStranger*
- `Telegram
LMGTFY\_bot <https://github.com/GabrielRF/telegram-lmgtfy_bot>`__ by
*GabrielRF*
- `Telegram
UrlProBot <https://github.com/GabrielRF/telegram-urlprobot>`__ by
*GabrielRF*
- `Telegram Proxy
Bot <https://bitbucket.org/master_groosha/telegram-proxy-bot>`__ by
*Groosha* - A simple BITM (bot-in-the-middle) for Telegram acting as
some kind of "proxy".
- `Telegram Proxy Bot <https://github.com/mrgigabyte/proxybot>`__ by
*mrgigabyte* -
``Credits for the original version of this bot goes to`` **Groosha**
``, simply added certain features which I thought were needed``.
- `RadRetroRobot <https://github.com/Tronikart/RadRetroRobot>`__ by
*Tronikart* - Multifunctional Telegram Bot RadRetroRobot.
- `League of Legends bot <https://telegram.me/League_of_Legends_bot>`__
(`source <https://github.com/i32ropie/lol>`__) by *i32ropie*
- `NeoBot <https://github.com/neoranger/NeoBot>`__ by *neoranger*
- `TagAlertBot <https://github.com/pitasi/TagAlertBot>`__ by *pitasi*
Want to have your bot listed here? Send a Telegram message to @eternnoir
or @pevdh.
.. |Download Month| image:: https://img.shields.io/pypi/v/pyTelegramBotAPI.svg
:target: https://pypi.python.org/pypi/pyTelegramBotAPI
.. |Build Status| image:: https://travis-ci.org/eternnoir/pyTelegramBotAPI.svg?branch=master
:target: https://travis-ci.org/eternnoir/pyTelegramBotAPI
.. |Download Month| image:: https://img.shields.io/pypi/dm/pyTelegramBotAPI.svg
:target: https://pypi.python.org/pypi/pyTelegramBotAPI

View File

@ -5,7 +5,7 @@ import sys
import logging
from telebot import types
API_TOKEN = '<api_token>'
API_TOKEN = '<TOKEN>'
bot = telebot.TeleBot(API_TOKEN)
telebot.logger.setLevel(logging.DEBUG)
@ -14,23 +14,24 @@ telebot.logger.setLevel(logging.DEBUG)
@bot.inline_handler(lambda query: query.query == 'text')
def query_text(inline_query):
try:
r = types.InlineQueryResultArticle('1', 'Result', inline_query.query)
r2 = types.InlineQueryResultArticle('2', 'Result2', inline_query.query)
r = types.InlineQueryResultArticle('1', 'Result1', types.InputTextMessageContent('hi'))
r2 = types.InlineQueryResultArticle('2', 'Result2', types.InputTextMessageContent('hi'))
bot.answer_inline_query(inline_query.id, [r, r2])
except Exception as e:
print(e)
@bot.inline_handler(lambda query: query.query == 'photo')
@bot.inline_handler(lambda query: query.query == 'photo1')
def query_photo(inline_query):
try:
r = types.InlineQueryResultPhoto('1',
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/kitten.jpg',
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/kitten.jpg')
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/kitten.jpg',
input_message_content=types.InputTextMessageContent('hi'))
r2 = types.InlineQueryResultPhoto('2',
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/rooster.jpg',
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/rooster.jpg')
bot.answer_inline_query(inline_query.id, [r, r2])
bot.answer_inline_query(inline_query.id, [r, r2], cache_time=1)
except Exception as e:
print(e)

View File

@ -48,7 +48,7 @@ def index():
@app.route(WEBHOOK_URL_PATH, methods=['POST'])
def webhook():
if flask.request.headers.get('content-type') == 'application/json':
json_string = flask.request.get_data()
json_string = flask.request.get_data().decode('utf-8')
update = telebot.types.Update.de_json(json_string)
bot.process_new_messages([update.message])
return ''

View File

@ -1,12 +1,13 @@
#!/usr/bin/env python
from setuptools import setup
from io import open
def readme():
with open('README.rst') as f:
with open('README.rst', encoding='utf-8') as f:
return f.read()
setup(name='pyTelegramBotAPI',
version='1.4.1',
version='2.0.5',
description='Python Telegram bot api. ',
long_description=readme(),
author='eternnoir',
@ -15,7 +16,7 @@ setup(name='pyTelegramBotAPI',
packages=['telebot'],
license='GPL2',
keywords='telegram bot api tools',
install_requires=['pytest', 'requests', 'six'],
install_requires=['requests', 'six'],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Programming Language :: Python :: 2',

View File

@ -11,7 +11,7 @@ import logging
logger = logging.getLogger('TeleBot')
formatter = logging.Formatter(
'%(asctime)s (%(filename)s:%(lineno)d %(threadName)s) %(levelname)s - %(name)s: "%(message)s"'
'%(asctime)s (%(filename)s:%(lineno)d %(threadName)s) %(levelname)s - %(name)s: "%(message)s"'
)
console_output_handler = logging.StreamHandler(sys.stderr)
@ -68,6 +68,7 @@ class TeleBot:
self.message_handlers = []
self.inline_handlers = []
self.chosen_inline_handlers = []
self.callback_query_handlers = []
self.threaded = threaded
if self.threaded:
@ -118,9 +119,13 @@ class TeleBot:
logger.debug('Skipped {0} pending messages'.format(self.__skip_updates()))
self.skip_pending = False
updates = self.get_updates(offset=(self.last_update_id + 1), timeout=timeout)
self.process_new_updates(updates)
def process_new_updates(self, updates):
new_messages = []
new_inline_querys = []
new_chosen_inline_results = []
new_callback_querys = []
for update in updates:
if update.update_id > self.last_update_id:
self.last_update_id = update.update_id
@ -130,6 +135,8 @@ class TeleBot:
new_inline_querys.append(update.inline_query)
if update.chosen_inline_result:
new_chosen_inline_results.append(update.chosen_inline_result)
if update.callback_query:
new_callback_querys.append(update.callback_query)
logger.debug('Received {0} new updates'.format(len(updates)))
if len(new_messages) > 0:
self.process_new_messages(new_messages)
@ -137,6 +144,8 @@ class TeleBot:
self.process_new_inline_query(new_inline_querys)
if len(new_chosen_inline_results) > 0:
self.process_new_chosen_inline_query(new_chosen_inline_results)
if len(new_callback_querys) > 0:
self.process_new_callback_query(new_callback_querys)
def process_new_messages(self, new_messages):
self._append_pre_next_step_handler()
@ -151,6 +160,9 @@ class TeleBot:
def process_new_chosen_inline_query(self, new_chosen_inline_querys):
self._notify_command_handlers(self.chosen_inline_handlers, new_chosen_inline_querys)
def process_new_callback_query(self, new_callback_querys):
self._notify_command_handlers(self.callback_query_handlers, new_callback_querys)
def __notify_update(self, new_messages):
for listener in self.update_listener:
self.__exec_task(listener, new_messages)
@ -179,9 +191,9 @@ class TeleBot:
polling_thread = util.WorkerThread(name="PollingThread")
or_event = util.OrEvent(
polling_thread.done_event,
polling_thread.exception_event,
self.worker_pool.exception_event
polling_thread.done_event,
polling_thread.exception_event,
self.worker_pool.exception_event
)
while not self.__stop_polling.wait(interval):
@ -274,7 +286,7 @@ class TeleBot:
return types.UserProfilePhotos.de_json(result)
def send_message(self, chat_id, text, disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None):
parse_mode=None, disable_notification=None):
"""
Use this method to send text messages.
@ -287,23 +299,27 @@ class TeleBot:
:param reply_to_message_id:
:param reply_markup:
:param parse_mode:
:param disable_notification: Boolean, Optional. Sends the message silently.
:return: API reply.
"""
return types.Message.de_json(
apihelper.send_message(self.token, chat_id, text, disable_web_page_preview, reply_to_message_id,
reply_markup, parse_mode))
apihelper.send_message(self.token, chat_id, text, disable_web_page_preview, reply_to_message_id,
reply_markup, parse_mode, disable_notification))
def forward_message(self, chat_id, from_chat_id, message_id):
def forward_message(self, chat_id, from_chat_id, message_id, disable_notification=None):
"""
Use this method to forward messages of any kind.
:param disable_notification:
:param chat_id: which chat to forward
:param from_chat_id: which chat message from
:param message_id: message id
:return: API reply.
"""
return types.Message.de_json(apihelper.forward_message(self.token, chat_id, from_chat_id, message_id))
return types.Message.de_json(
apihelper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification))
def send_photo(self, chat_id, photo, caption=None, reply_to_message_id=None, reply_markup=None):
def send_photo(self, chat_id, photo, caption=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None):
"""
Use this method to send photos.
:param chat_id:
@ -314,10 +330,11 @@ class TeleBot:
:return: API reply.
"""
return types.Message.de_json(
apihelper.send_photo(self.token, chat_id, photo, caption, reply_to_message_id, reply_markup))
apihelper.send_photo(self.token, chat_id, photo, caption, reply_to_message_id, reply_markup,
disable_notification))
def send_audio(self, chat_id, audio, duration=None, performer=None, title=None, reply_to_message_id=None,
reply_markup=None):
reply_markup=None, disable_notification=None):
"""
Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .mp3 format.
:param chat_id:Unique identifier for the message recipient
@ -330,10 +347,11 @@ class TeleBot:
:return: Message
"""
return types.Message.de_json(
apihelper.send_audio(self.token, chat_id, audio, duration, performer, title, reply_to_message_id,
reply_markup))
apihelper.send_audio(self.token, chat_id, audio, duration, performer, title, reply_to_message_id,
reply_markup, disable_notification))
def send_voice(self, chat_id, voice, duration=None, reply_to_message_id=None, reply_markup=None):
def send_voice(self, chat_id, voice, duration=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None):
"""
Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message.
:param chat_id:Unique identifier for the message recipient.
@ -344,9 +362,10 @@ class TeleBot:
:return: Message
"""
return types.Message.de_json(
apihelper.send_voice(self.token, chat_id, voice, duration, reply_to_message_id, reply_markup))
apihelper.send_voice(self.token, chat_id, voice, duration, reply_to_message_id, reply_markup,
disable_notification))
def send_document(self, chat_id, data, reply_to_message_id=None, reply_markup=None):
def send_document(self, chat_id, data, reply_to_message_id=None, reply_markup=None, disable_notification=None):
"""
Use this method to send general files.
:param chat_id:
@ -356,9 +375,10 @@ class TeleBot:
:return: API reply.
"""
return types.Message.de_json(
apihelper.send_data(self.token, chat_id, data, 'document', reply_to_message_id, reply_markup))
apihelper.send_data(self.token, chat_id, data, 'document', reply_to_message_id, reply_markup,
disable_notification))
def send_sticker(self, chat_id, data, reply_to_message_id=None, reply_markup=None):
def send_sticker(self, chat_id, data, reply_to_message_id=None, reply_markup=None, disable_notification=None):
"""
Use this method to send .webp stickers.
:param chat_id:
@ -368,9 +388,11 @@ class TeleBot:
:return: API reply.
"""
return types.Message.de_json(
apihelper.send_data(self.token, chat_id, data, 'sticker', reply_to_message_id, reply_markup))
apihelper.send_data(self.token, chat_id, data, 'sticker', reply_to_message_id, reply_markup,
disable_notification))
def send_video(self, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None):
def send_video(self, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None):
"""
Use this method to send video files, Telegram clients support mp4 videos.
:param chat_id: Integer : Unique identifier for the message recipient — User or GroupChat id
@ -382,9 +404,11 @@ class TeleBot:
:return:
"""
return types.Message.de_json(
apihelper.send_video(self.token, chat_id, data, duration, caption, reply_to_message_id, reply_markup))
apihelper.send_video(self.token, chat_id, data, duration, caption, reply_to_message_id, reply_markup,
disable_notification))
def send_location(self, chat_id, latitude, longitude, reply_to_message_id=None, reply_markup=None):
def send_location(self, chat_id, latitude, longitude, reply_to_message_id=None, reply_markup=None,
disable_notification=None):
"""
Use this method to send point on the map.
:param chat_id:
@ -395,7 +419,35 @@ class TeleBot:
:return: API reply.
"""
return types.Message.de_json(
apihelper.send_location(self.token, chat_id, latitude, longitude, reply_to_message_id, reply_markup))
apihelper.send_location(self.token, chat_id, latitude, longitude, reply_to_message_id, reply_markup,
disable_notification))
def send_venue(self, chat_id, latitude, longitude, title, address, foursquare_id=None, disable_notification=None,
reply_to_message_id=None, reply_markup=None):
"""
Use this method to send information about a venue.
:param chat_id: Integer or String : Unique identifier for the target chat or username of the target channel
:param latitude: Float : Latitude of the venue
:param longitude: Float : Longitude of the venue
:param title: String : Name of the venue
:param address: String : Address of the venue
:param foursquare_id: String : Foursquare identifier of the venue
:param disable_notification:
:param reply_to_message_id:
:param reply_markup:
:return:
"""
return types.Message.de_json(
apihelper.send_venue(self.token, chat_id, latitude, longitude, title, address, foursquare_id,
disable_notification, reply_to_message_id, reply_markup)
)
def send_contact(self, chat_id, phone_number, first_name, last_name=None, disable_notification=None,
reply_to_message_id=None, reply_markup=None):
return types.Message.de_json(
apihelper.send_contact(self.token, chat_id, phone_number, first_name, last_name, disable_notification,
reply_to_message_id, reply_markup)
)
def send_chat_action(self, chat_id, action):
"""
@ -409,13 +461,47 @@ class TeleBot:
"""
return apihelper.send_chat_action(self.token, chat_id, action)
def kick_chat_member(self, chat_id, user_id):
"""
Use this method to kick a user from a group or a supergroup.
:param chat_id: Int or string : Unique identifier for the target group or username of the target supergroup
:param user_id: Int : Unique identifier of the target user
:return: types.Message
"""
return apihelper.kick_chat_member(self.token, chat_id, user_id)
def unban_chat_member(self, chat_id, user_id):
return apihelper.unban_chat_member(self.token, chat_id, user_id)
def answer_callback_query(self, callback_query_id, text=None, show_alert=None):
return apihelper.answer_callback_query(self.token, callback_query_id, text, show_alert)
def edit_message_text(self, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None,
disable_web_page_preview=None, reply_markup=None):
result = apihelper.edit_message_text(self.token, text, chat_id, message_id, inline_message_id, parse_mode,
disable_web_page_preview, reply_markup)
if type(result) == bool: # if edit inline message return is bool not Message.
return result
return types.Message.de_json(result)
def edit_message_reply_markup(self, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
return types.Message.de_json(
apihelper.edit_message_reply_markup(self.token, chat_id, message_id, inline_message_id, reply_markup)
)
def edit_message_caption(self, caption, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
return types.Message.de_json(
apihelper.edit_message_caption(self.token, caption, chat_id, message_id, inline_message_id, reply_markup)
)
def reply_to(self, message, text, **kwargs):
"""
Convenience function for `send_message(message.chat.id, text, reply_to_message_id=message.message_id, **kwargs)`
"""
return self.send_message(message.chat.id, text, reply_to_message_id=message.message_id, **kwargs)
def answer_inline_query(self, inline_query_id, results, cache_time=None, is_personal=None, next_offset=None):
def answer_inline_query(self, inline_query_id, results, cache_time=None, is_personal=None, next_offset=None,
switch_pm_text=None, switch_pm_parameter=None):
"""
Use this method to send answers to an inline query. On success, True is returned.
No more than 50 results per query are allowed.
@ -424,9 +510,24 @@ class TeleBot:
:param cache_time: The maximum amount of time in seconds that the result of the inline query may be cached on the server.
:param is_personal: Pass True, if results may be cached on the server side only for the user that sent the query.
:param next_offset: Pass the offset that a client should send in the next query with the same text to receive more results.
:param switch_pm_parameter: If passed, clients will display a button with specified text that switches the user
to a private chat with the bot and sends the bot a start message with the parameter switch_pm_parameter
:param switch_pm_text: Parameter for the start message sent to the bot when user presses the switch button
:return: True means success.
"""
return apihelper.answer_inline_query(self.token, inline_query_id, results, cache_time, is_personal, next_offset)
return apihelper.answer_inline_query(self.token, inline_query_id, results, cache_time, is_personal, next_offset,
switch_pm_text, switch_pm_parameter)
def answer_callback_query(self, callback_query_id, text=None, show_alert=None):
"""
Use this method to send answers to callback queries sent from inline keyboards. The answer will be displayed to
the user as a notification at the top of the chat screen or as an alert.
:param callback_query_id:
:param text:
:param show_alert:
:return:
"""
return apihelper.answer_callback_query(self.token, callback_query_id, text, show_alert)
def register_for_reply(self, message, callback):
"""
@ -521,41 +622,81 @@ class TeleBot:
:param content_types: This commands' supported content types. Must be a list. Defaults to ['text'].
"""
def decorator(fn):
handler_dict = {'function': fn}
filters = {'content_types': content_types}
if regexp:
filters['regexp'] = regexp
if func:
filters['lambda'] = func
if commands:
filters['commands'] = commands
handler_dict['filters'] = filters
self.message_handlers.append(handler_dict)
return fn
def decorator(handler):
self.add_message_handler(handler, commands, regexp, func, content_types)
return handler
return decorator
def add_message_handler(self, handler, commands=None, regexp=None, func=None, content_types=None):
if content_types is None:
content_types = ['text']
filters = {'content_types': content_types}
if regexp:
filters['regexp'] = regexp
if func:
filters['lambda'] = func
if commands:
filters['commands'] = commands
handler_dict = {
'function': handler,
'filters': filters
}
self.message_handlers.append(handler_dict)
def inline_handler(self, func):
def decorator(fn):
handler_dict = {'function': fn}
filters = {'lambda': func}
handler_dict['filters'] = filters
self.inline_handlers.append(handler_dict)
return fn
def decorator(handler):
self.add_inline_handler(handler, func)
return handler
return decorator
def add_inline_handler(self, handler, func):
filters = {'lambda': func}
handler_dict = {
'function': handler,
'filters': filters
}
self.inline_handlers.append(handler_dict)
def chosen_inline_handler(self, func):
def decorator(fn):
handler_dict = {'function': fn}
filters = {'lambda': func}
handler_dict['filters'] = filters
self.chosen_inline_handlers.append(handler_dict)
return fn
def decorator(handler):
self.add_chosen_inline_handler(handler, func)
return handler
return decorator
def add_chosen_inline_handler(self, handler, func):
filters = {'lambda': func}
handler_dict = {
'function': handler,
'filters': filters
}
self.chosen_inline_handlers.append(handler_dict)
def callback_query_handler(self, func):
def decorator(handler):
self.add_callback_query_handler(handler, func)
return decorator
def add_callback_query_handler(self, handler, func):
filters = {'lambda': func}
handler_dict = {
'function': handler,
'filters': filters
}
self.callback_query_handlers.append(handler_dict)
@staticmethod
def _test_message_handler(message_handler, message):
for filter, filter_value in six.iteritems(message_handler['filters']):

View File

@ -10,6 +10,9 @@ logger = telebot.logger
API_URL = "https://api.telegram.org/bot{0}/{1}"
FILE_URL = "https://api.telegram.org/file/bot{0}/{1}"
CONNECT_TIMEOUT = 3.5
READ_TIMEOUT = 9999
def _make_request(token, method_name, method='get', params=None, files=None, base_url=API_URL):
"""
@ -23,7 +26,10 @@ def _make_request(token, method_name, method='get', params=None, files=None, bas
"""
request_url = base_url.format(token, method_name)
logger.debug("Request: method={0} url={1} params={2} files={3}".format(method, request_url, params, files))
result = requests.request(method, request_url, params=params, files=files)
read_timeout = READ_TIMEOUT
if params:
if 'timeout' in params: read_timeout = params['timeout'] + 10
result = requests.request(method, request_url, params=params, files=files, timeout=(CONNECT_TIMEOUT, read_timeout))
logger.debug("The server returned: '{0}'".format(result.text.encode('utf8')))
return _check_result(method_name, result)['result']
@ -81,7 +87,7 @@ def download_file(token, file_path):
def send_message(token, chat_id, text, disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None):
parse_mode=None, disable_notification=None):
"""
Use this method to send text messages. On success, the sent Message is returned.
:param token:
@ -102,6 +108,8 @@ def send_message(token, chat_id, text, disable_web_page_preview=None, reply_to_m
payload['reply_markup'] = _convert_markup(reply_markup)
if parse_mode:
payload['parse_mode'] = parse_mode
if disable_notification:
payload['disable_notification'] = disable_notification
return _make_request(token, method_url, params=payload, method='post')
@ -139,13 +147,16 @@ def get_user_profile_photos(token, user_id, offset=None, limit=None):
return _make_request(token, method_url, params=payload)
def forward_message(token, chat_id, from_chat_id, message_id):
def forward_message(token, chat_id, from_chat_id, message_id, disable_notification=None):
method_url = r'forwardMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if disable_notification:
payload['disable_notification'] = disable_notification
return _make_request(token, method_url, params=payload)
def send_photo(token, chat_id, photo, caption=None, reply_to_message_id=None, reply_markup=None):
def send_photo(token, chat_id, photo, caption=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None):
method_url = r'sendPhoto'
payload = {'chat_id': chat_id}
files = None
@ -159,12 +170,47 @@ def send_photo(token, chat_id, photo, caption=None, reply_to_message_id=None, re
payload['reply_to_message_id'] = reply_to_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
if disable_notification:
payload['disable_notification'] = disable_notification
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_location(token, chat_id, latitude, longitude, reply_to_message_id=None, reply_markup=None):
def send_location(token, chat_id, latitude, longitude, reply_to_message_id=None, reply_markup=None,
disable_notification=None):
method_url = r'sendLocation'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
if reply_to_message_id:
payload['reply_to_message_id'] = reply_to_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
if disable_notification:
payload['disable_notification'] = disable_notification
return _make_request(token, method_url, params=payload)
def send_venue(token, chat_id, latitude, longitude, title, address, foursquare_id=None, disable_notification=None,
reply_to_message_id=None, reply_markup=None):
method_url = r'sendVenue'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address}
if foursquare_id:
payload['foursquare_id'] = foursquare_id
if disable_notification:
payload['disable_notification'] = disable_notification
if reply_to_message_id:
payload['reply_to_message_id'] = reply_to_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload)
def send_contact(token, chat_id, phone_number, first_name, last_name=None, disable_notification=None,
reply_to_message_id=None, reply_markup=None):
method_url = r'sendContact'
payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name}
if last_name:
payload['last_name'] = last_name
if disable_notification:
payload['disable_notification'] = disable_notification
if reply_to_message_id:
payload['reply_to_message_id'] = reply_to_message_id
if reply_markup:
@ -178,7 +224,8 @@ def send_chat_action(token, chat_id, action):
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):
def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None):
method_url = r'sendVideo'
payload = {'chat_id': chat_id}
files = None
@ -194,10 +241,13 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa
payload['reply_to_message_id'] = reply_to_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
if disable_notification:
payload['disable_notification'] = disable_notification
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_voice(token, chat_id, voice, duration=None, reply_to_message_id=None, reply_markup=None):
def send_voice(token, chat_id, voice, duration=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None):
method_url = r'sendVoice'
payload = {'chat_id': chat_id}
files = None
@ -211,11 +261,13 @@ def send_voice(token, chat_id, voice, duration=None, reply_to_message_id=None, r
payload['reply_to_message_id'] = reply_to_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
if disable_notification:
payload['disable_notification'] = disable_notification
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_audio(token, chat_id, audio, duration=None, performer=None, title=None, reply_to_message_id=None,
reply_markup=None):
reply_markup=None, disable_notification=None):
method_url = r'sendAudio'
payload = {'chat_id': chat_id}
files = None
@ -233,10 +285,12 @@ def send_audio(token, chat_id, audio, duration=None, performer=None, title=None,
payload['reply_to_message_id'] = reply_to_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
if disable_notification:
payload['disable_notification'] = disable_notification
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None):
def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None, disable_notification=None):
method_url = get_method_by_type(data_type)
payload = {'chat_id': chat_id}
files = None
@ -248,6 +302,8 @@ def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_m
payload['reply_to_message_id'] = reply_to_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
if disable_notification:
payload['disable_notification'] = disable_notification
return _make_request(token, method_url, params=payload, files=files, method='post')
@ -258,16 +314,94 @@ def get_method_by_type(data_type):
return r'sendSticker'
def answer_inline_query(token, inline_query_id, results, cache_time=None, is_personal=None, next_offset=None):
def kick_chat_member(token, chat_id, user_id):
method_url = 'kickChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
return _make_request(token, method_url, params=payload, method='post')
def unban_chat_member(token, chat_id, user_id):
method_url = 'unbanChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
return _make_request(token, method_url, params=payload, method='post')
# Updating messages
def edit_message_text(token, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None,
disable_web_page_preview=None, reply_markup=None):
method_url = r'editMessageText'
payload = {'text': text}
if chat_id:
payload['chat_id'] = chat_id
if message_id:
payload['message_id'] = message_id
if inline_message_id:
payload['inline_message_id'] = inline_message_id
if parse_mode:
payload['parse_mode'] = parse_mode
if disable_web_page_preview:
payload['disable_web_page_preview'] = disable_web_page_preview
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload)
def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
method_url = r'editMessageCaption'
payload = {'caption': caption}
if chat_id:
payload['chat_id'] = chat_id
if message_id:
payload['message_id'] = message_id
if inline_message_id:
payload['inline_message_id'] = inline_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload)
def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
method_url = r'editMessageReplyMarkup'
payload = {}
if chat_id:
payload['chat_id'] = chat_id
if message_id:
payload['message_id'] = message_id
if inline_message_id:
payload['inline_message_id'] = inline_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload)
# InlineQuery
def answer_callback_query(token, callback_query_id, text=None, show_alert=None):
method_url = 'answerCallbackQuery'
payload = {'callback_query_id': callback_query_id}
if text:
payload['text'] = text
if show_alert:
payload['show_alert'] = show_alert
return _make_request(token, method_url, params=payload, method='post')
def answer_inline_query(token, inline_query_id, results, cache_time=None, is_personal=None, next_offset=None,
switch_pm_text=None, switch_pm_parameter=None):
method_url = 'answerInlineQuery'
payload = {'inline_query_id': inline_query_id, 'results': _convert_inline_results(results)}
if cache_time:
payload['cache_time'] = cache_time
if is_personal:
payload['is_personal'] = is_personal
if next_offset:
if next_offset is not None:
payload['next_offset'] = next_offset
return _make_request(token, method_url, params=payload)
if switch_pm_text:
payload['switch_pm_text'] = switch_pm_text
if switch_pm_parameter:
payload['switch_pm_parameter'] = switch_pm_parameter
return _make_request(token, method_url, params=payload, method='post')
def _convert_inline_results(results):

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import threading
import re
import sys
import six
from six import string_types
@ -224,3 +225,19 @@ def OrEvent(*events):
or_event.wait = busy_wait
changed()
return or_event
def extract_arguments(text):
"""
Returns the argument after the command.
Examples:
extract_arguments("/get name"): 'name'
extract_arguments("/get"): ''
extract_arguments("/get@botName name"): 'name'
:param text: String to extract the arguments from a command
:return: the arguments if `text` is a command (according to is_command), else None.
"""
regexp = re.compile("\/\w*(@\w*)*\s*([\s\S]*)",re.IGNORECASE)
result = regexp.match(text)
return result.group(2) if is_command(text) else None

View File

@ -101,6 +101,16 @@ class TestTeleBot:
ret_msg = tb.send_message(CHAT_ID, markdown, parse_mode="Markdown")
assert ret_msg.message_id
def test_send_message_with_disable_notification(self):
tb = telebot.TeleBot(TOKEN)
markdown = """
*bold text*
_italic text_
[text](URL)
"""
ret_msg = tb.send_message(CHAT_ID, markdown, parse_mode="Markdown", disable_notification=True)
assert ret_msg.message_id
def test_send_file(self):
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
tb = telebot.TeleBot(TOKEN)
@ -110,18 +120,39 @@ class TestTeleBot:
ret_msg = tb.send_document(CHAT_ID, ret_msg.document.file_id)
assert ret_msg.message_id
def test_send_file_dis_noti(self):
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_document(CHAT_ID, file_data, disable_notification=True)
assert ret_msg.message_id
ret_msg = tb.send_document(CHAT_ID, ret_msg.document.file_id)
assert ret_msg.message_id
def test_send_video(self):
file_data = open('./test_data/test_video.mp4', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_video(CHAT_ID, file_data)
assert ret_msg.message_id
def test_send_video_dis_noti(self):
file_data = open('./test_data/test_video.mp4', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_video(CHAT_ID, file_data, disable_notification=True)
assert ret_msg.message_id
def test_send_video_more_params(self):
file_data = open('./test_data/test_video.mp4', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_video(CHAT_ID, file_data, 1)
assert ret_msg.message_id
def test_send_video_more_params_dis_noti(self):
file_data = open('./test_data/test_video.mp4', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_video(CHAT_ID, file_data, 1, disable_notification=True)
assert ret_msg.message_id
def test_send_file_exception(self):
tb = telebot.TeleBot(TOKEN)
try:
@ -140,6 +171,15 @@ class TestTeleBot:
ret_msg = tb.send_photo(CHAT_ID, ret_msg.photo[0].file_id)
assert ret_msg.message_id
def test_send_photo_dis_noti(self):
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_photo(CHAT_ID, file_data)
assert ret_msg.message_id
ret_msg = tb.send_photo(CHAT_ID, ret_msg.photo[0].file_id, disable_notification=True)
assert ret_msg.message_id
def test_send_audio(self):
file_data = open('./test_data/record.mp3', 'rb')
tb = telebot.TeleBot(TOKEN)
@ -148,12 +188,26 @@ class TestTeleBot:
assert ret_msg.audio.performer == 'eternnoir'
assert ret_msg.audio.title == 'pyTelegram'
def test_send_audio_dis_noti(self):
file_data = open('./test_data/record.mp3', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_audio(CHAT_ID, file_data, 1, 'eternnoir', 'pyTelegram', disable_notification=True)
assert ret_msg.content_type == 'audio'
assert ret_msg.audio.performer == 'eternnoir'
assert ret_msg.audio.title == 'pyTelegram'
def test_send_voice(self):
file_data = open('./test_data/record.ogg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_voice(CHAT_ID, file_data)
assert ret_msg.voice.mime_type == 'audio/ogg'
def test_send_voice_dis_noti(self):
file_data = open('./test_data/record.ogg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_voice(CHAT_ID, file_data, disable_notification=True)
assert ret_msg.voice.mime_type == 'audio/ogg'
def test_get_file(self):
file_data = open('./test_data/record.ogg', 'rb')
tb = telebot.TeleBot(TOKEN)
@ -162,12 +216,55 @@ class TestTeleBot:
file_info = tb.get_file(file_id)
assert file_info.file_id == file_id
def test_get_file_dis_noti(self):
file_data = open('./test_data/record.ogg', 'rb')
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_voice(CHAT_ID, file_data, disable_notification=True)
file_id = ret_msg.voice.file_id
file_info = tb.get_file(file_id)
assert file_info.file_id == file_id
def test_send_message(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_message(CHAT_ID, text)
assert ret_msg.message_id
def test_send_message_dis_noti(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_message(CHAT_ID, text, disable_notification=True)
assert ret_msg.message_id
def test_send_message_with_markup(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
markup = types.ReplyKeyboardMarkup()
markup.add(types.KeyboardButton("1"))
markup.add(types.KeyboardButton("2"))
ret_msg = tb.send_message(CHAT_ID, text, disable_notification=True, reply_markup=markup)
assert ret_msg.message_id
def test_send_message_with_markup_use_string(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
markup = types.ReplyKeyboardMarkup()
markup.add("1")
markup.add("2")
markup.add("3")
markup.add("4")
ret_msg = tb.send_message(CHAT_ID, text, disable_notification=True, reply_markup=markup)
assert ret_msg.message_id
def test_send_message_with_inlinemarkup(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton("Google", url="http://www.google.com"))
markup.add(types.InlineKeyboardButton("Yahoo", url="http://www.yahoo.com"))
ret_msg = tb.send_message(CHAT_ID, text, disable_notification=True, reply_markup=markup)
assert ret_msg.message_id
def test_forward_message(self):
text = 'CI forward_message Test Message'
tb = telebot.TeleBot(TOKEN)
@ -175,6 +272,13 @@ class TestTeleBot:
ret_msg = tb.forward_message(CHAT_ID, CHAT_ID, msg.message_id)
assert ret_msg.forward_from
def test_forward_message_dis_noti(self):
text = 'CI forward_message Test Message'
tb = telebot.TeleBot(TOKEN)
msg = tb.send_message(CHAT_ID, text)
ret_msg = tb.forward_message(CHAT_ID, CHAT_ID, msg.message_id, disable_notification=True)
assert ret_msg.forward_from
def test_reply_to(self):
text = 'CI reply_to Test Message'
tb = telebot.TeleBot(TOKEN)
@ -203,6 +307,28 @@ class TestTeleBot:
assert int(ret_msg.location.longitude) == int(lon)
assert int(ret_msg.location.latitude) == int(lat)
def test_send_location_dis_noti(self):
tb = telebot.TeleBot(TOKEN)
lat = 26.3875591
lon = -161.2901042
ret_msg = tb.send_location(CHAT_ID, lat, lon, disable_notification=True)
assert int(ret_msg.location.longitude) == int(lon)
assert int(ret_msg.location.latitude) == int(lat)
def test_send_venue(self):
tb = telebot.TeleBot(TOKEN)
lat = 26.3875591
lon = -161.2901042
ret_msg = tb.send_venue(CHAT_ID, lat, lon, "Test Venue", "1123 Test Venue address")
assert ret_msg.venue.title == "Test Venue"
def test_send_venue_dis_noti(self):
tb = telebot.TeleBot(TOKEN)
lat = 26.3875591
lon = -161.2901042
ret_msg = tb.send_venue(CHAT_ID, lat, lon, "Test Venue", "1123 Test Venue address", disable_notification=True)
assert ret_msg.venue.title == "Test Venue"
def test_Chat(self):
tb = telebot.TeleBot(TOKEN)
me = tb.get_me()
@ -210,6 +336,24 @@ class TestTeleBot:
assert me.id == msg.from_user.id
assert msg.chat.id == int(CHAT_ID)
def test_edit_message_text(self):
tb = telebot.TeleBot(TOKEN)
msg = tb.send_message(CHAT_ID, 'Test')
new_msg = tb.edit_message_text('Edit test', chat_id=CHAT_ID, message_id=msg.message_id)
assert new_msg.text == 'Edit test'
def test_edit_markup(self):
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton("Google", url="http://www.google.com"))
markup.add(types.InlineKeyboardButton("Yahoo", url="http://www.yahoo.com"))
ret_msg = tb.send_message(CHAT_ID, text, disable_notification=True, reply_markup=markup)
markup.add(types.InlineKeyboardButton("Google2", url="http://www.google.com"))
markup.add(types.InlineKeyboardButton("Yahoo2", url="http://www.yahoo.com"))
new_msg = tb.edit_message_reply_markup(chat_id=CHAT_ID, message_id=ret_msg.message_id, reply_markup=markup)
assert new_msg.message_id
def create_text_message(self, text):
params = {'text': text}
chat = types.User(11, 'test')

View File

@ -127,3 +127,31 @@ def test_json_chat():
assert chat.type == 'group'
assert chat.title == 'Test Title'
def test_InlineQueryResultCachedPhoto():
iq = types.InlineQueryResultCachedPhoto('aaa', 'Fileid')
json_str = iq.to_json()
assert 'aa' in json_str
assert 'Fileid' in json_str
assert 'caption' not in json_str
def test_InlineQueryResultCachedPhoto_with_title():
iq = types.InlineQueryResultCachedPhoto('aaa', 'Fileid', title='Title')
json_str = iq.to_json()
assert 'aa' in json_str
assert 'Fileid' in json_str
assert 'Title' in json_str
assert 'caption' not in json_str
def test_InlineQueryResultCachedPhoto_with_markup():
markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton("Google", url="http://www.google.com"))
markup.add(types.InlineKeyboardButton("Yahoo", url="http://www.yahoo.com"))
iq = types.InlineQueryResultCachedPhoto('aaa', 'Fileid', title='Title', reply_markup=markup)
json_str = iq.to_json()
assert 'aa' in json_str
assert 'Fileid' in json_str
assert 'Title' in json_str
assert 'caption' not in json_str
assert 'reply_markup' in json_str