mirror of
https://github.com/eternnoir/pyTelegramBotAPI.git
synced 2023-08-10 21:12:57 +03:00
Merge branch 'redesign-message-handlers' into 'develop'
This commit is contained in:
commit
f2971c5d6c
33
README.md
33
README.md
@ -130,7 +130,26 @@ All [API methods](https://core.telegram.org/bots/api#available-methods) are loca
|
||||
Outlined below are some general use cases of the API.
|
||||
|
||||
#### Message handlers
|
||||
A message handler is a function which is decorated with the `message_handler` decorator of a TeleBot instance. The following examples illustrate the possibilities of message handlers:
|
||||
A message handler is a function that is decorated with the `message_handler` decorator of a TeleBot instance. Message handlers consist of one or multiple filters.
|
||||
Each filter much return True for a certain message in order for a message handler to become eligible to handle that message. A message handler is declared in the following way (provided `bot` is an instance of TeleBot):
|
||||
```python
|
||||
@bot.message_handler(filters)
|
||||
def function_name(message):
|
||||
bot.reply_to(message, "This is a message handler")
|
||||
```
|
||||
`function_name` is not bound to any restrictions. Any function name is permitted with message handlers. The function must accept at most one argument, which will be the message that the function must handle.
|
||||
`filters` is a list of keyword arguments.
|
||||
A filter is declared in the following manner: `name=argument`. One handler may have multiple filters.
|
||||
TeleBot supports the following filters:
|
||||
|
||||
|name|argument(s)|Condition|
|
||||
|:---:|---| ---|
|
||||
|content_types|list of strings (default `['text']`)|`True` if message.content_type is in the list of strings.|
|
||||
|regexp|a regular expression as a string|`True` if `re.search(regexp_arg)` returns `True` and `message.content_type == 'text'` (See [Python Regular Expressions](https://docs.python.org/2/library/re.html)|
|
||||
|commands|list of strings|`True` if `message.content_type == 'text'` and `message.text` starts with a command that is in the list of strings.|
|
||||
|func|a function (lambda or function reference)|`True` if the lambda or function reference returns `True`
|
||||
|
||||
Here are some examples of using the filters and message handlers:
|
||||
```python
|
||||
import telebot
|
||||
bot = telebot.TeleBot("TOKEN")
|
||||
@ -163,7 +182,7 @@ def test_message(message):
|
||||
def handle_text_doc(message)
|
||||
pass
|
||||
```
|
||||
*Note: all handlers are tested in the order in which they were declared*
|
||||
**Important: all handlers are tested in the order in which they were declared**
|
||||
#### TeleBot
|
||||
```python
|
||||
import telebot
|
||||
@ -338,15 +357,13 @@ If you prefer using web hooks to the getUpdates method, you can use the `process
|
||||
### Logging
|
||||
|
||||
You can use the Telebot module logger to log debug info about Telebot. Use `telebot.logger` to get the logger of the TeleBot module.
|
||||
It is possible to add custom logging Handlers to the logger. Refer to the [Python logging module page](https://docs.python.org/2/library/logging.html) for more info.
|
||||
|
||||
```python
|
||||
import logging
|
||||
|
||||
logger = telebot.logger
|
||||
formatter = logging.Formatter('[%(asctime)s] %(thread)d {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
|
||||
'%m-%d %H:%M:%S')
|
||||
ch = logging.StreamHandler(sys.stdout)
|
||||
logger.addHandler(ch)
|
||||
logger.setLevel(logging.DEBUG) # or use logging.INFO
|
||||
ch.setFormatter(formatter)
|
||||
telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console.
|
||||
```
|
||||
|
||||
## F.A.Q.
|
||||
|
@ -3,12 +3,18 @@ from __future__ import print_function
|
||||
|
||||
import threading
|
||||
import time
|
||||
import re
|
||||
import sys
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger('TeleBot')
|
||||
formatter = logging.Formatter('%(asctime)s (%(filename)s:%(lineno)d) %(levelname)s - %(name)s: "%(message)s"')
|
||||
|
||||
logging.basicConfig()
|
||||
logger = logging.getLogger('Telebot')
|
||||
import re
|
||||
console_output_handler = logging.StreamHandler(sys.stderr)
|
||||
console_output_handler.setFormatter(formatter)
|
||||
logger.addHandler(console_output_handler)
|
||||
|
||||
logger.setLevel(logging.ERROR)
|
||||
|
||||
from telebot import apihelper, types, util
|
||||
|
||||
@ -87,7 +93,7 @@ class TeleBot:
|
||||
if update.update_id > self.last_update_id:
|
||||
self.last_update_id = update.update_id
|
||||
new_messages.append(update.message)
|
||||
logger.debug('GET %d new messages' % len(new_messages))
|
||||
logger.debug('Received {} new messages'.format(len(new_messages)))
|
||||
if len(new_messages) > 0:
|
||||
self.process_new_messages(new_messages)
|
||||
|
||||
@ -124,10 +130,17 @@ class TeleBot:
|
||||
self.polling_thread.start()
|
||||
|
||||
if block:
|
||||
self.__stop_polling.wait()
|
||||
while self.polling_thread.is_alive:
|
||||
try:
|
||||
time.sleep(.1)
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Received KeyboardInterrupt. Stopping.")
|
||||
self.stop_polling()
|
||||
self.polling_thread.join()
|
||||
break
|
||||
|
||||
def __polling(self, none_stop, interval):
|
||||
logger.info('TeleBot: Started polling.')
|
||||
logger.info('Started polling.')
|
||||
|
||||
error_interval = .25
|
||||
while not self.__stop_polling.wait(interval):
|
||||
@ -137,13 +150,13 @@ class TeleBot:
|
||||
except apihelper.ApiException as e:
|
||||
if not none_stop:
|
||||
self.__stop_polling.set()
|
||||
logger.info("TeleBot: Exception occurred. Stopping.")
|
||||
logger.info("Exception occurred. Stopping.")
|
||||
else:
|
||||
time.sleep(error_interval)
|
||||
error_interval *= 2
|
||||
logger.error(e)
|
||||
|
||||
logger.info('TeleBot: Stopped polling.')
|
||||
logger.info('Stopped polling.')
|
||||
|
||||
def stop_polling(self):
|
||||
self.__stop_polling.set()
|
||||
@ -388,31 +401,38 @@ class TeleBot:
|
||||
:param func: Optional lambda function. The lambda receives the message to test as the first parameter. It must return True if the command should handle the message.
|
||||
:param content_types: This commands' supported content types. Must be a list. Defaults to ['text'].
|
||||
"""
|
||||
|
||||
def decorator(fn):
|
||||
func_dict = {'function': fn, 'content_types': content_types}
|
||||
handler_dict = {'function': fn}
|
||||
filters = {'content_types': content_types}
|
||||
if regexp:
|
||||
func_dict['regexp'] = regexp if 'text' in content_types else None
|
||||
filters['regexp'] = regexp
|
||||
if func:
|
||||
func_dict['lambda'] = func
|
||||
filters['lambda'] = func
|
||||
if commands:
|
||||
func_dict['commands'] = commands if 'text' in content_types else None
|
||||
self.message_handlers.append(func_dict)
|
||||
filters['commands'] = commands
|
||||
handler_dict['filters'] = filters
|
||||
self.message_handlers.append(handler_dict)
|
||||
return fn
|
||||
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def _test_message_handler(message_handler, message):
|
||||
if message.content_type not in message_handler['content_types']:
|
||||
for filter, filter_value in message_handler['filters'].iteritems():
|
||||
if not TeleBot._test_filter(filter, filter_value, message):
|
||||
return False
|
||||
if 'commands' in message_handler and message.content_type == 'text':
|
||||
return util.extract_command(message.text) in message_handler['commands']
|
||||
if 'regexp' in message_handler and message.content_type == 'text' and re.search(message_handler['regexp'],
|
||||
message.text):
|
||||
return True
|
||||
if 'lambda' in message_handler:
|
||||
return message_handler['lambda'](message)
|
||||
|
||||
@staticmethod
|
||||
def _test_filter(filter, filter_value, message):
|
||||
if filter == 'content_types':
|
||||
return message.content_type in filter_value
|
||||
if filter == 'regexp':
|
||||
return message.content_type == 'text' and re.search(filter_value, message.text)
|
||||
if filter == 'commands':
|
||||
return message.content_type == 'text' and util.extract_command(message.text) in filter_value
|
||||
if filter == 'func':
|
||||
return filter_value(message)
|
||||
return False
|
||||
|
||||
def _notify_command_handlers(self, new_messages):
|
||||
|
@ -19,8 +19,9 @@ def _make_request(token, method_name, method='get', params=None, files=None):
|
||||
:return: The result parsed to a JSON dictionary.
|
||||
"""
|
||||
request_url = telebot.API_URL + 'bot' + token + '/' + method_name
|
||||
logger.debug("Request: method={} url={} params={} files={}".format(method, request_url, params, files))
|
||||
result = requests.request(method, request_url, params=params, files=files)
|
||||
logger.debug(result.text)
|
||||
logger.debug("The server returned: '{}'".format(result.text))
|
||||
return _check_result(method_name, result)['result']
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user