mirror of
https://github.com/eternnoir/pyTelegramBotAPI.git
synced 2023-08-10 21:12:57 +03:00
Merge branch 'develop'
This commit is contained in:
commit
8e9837a587
12
README.md
12
README.md
@ -118,7 +118,7 @@ To start the bot, simply open up a terminal and enter `python echo_bot.py` to ru
|
||||
|
||||
All types are defined in types.py. They are all completely in line with the [Telegram API's definition of the types](https://core.telegram.org/bots/api#available-types), except for the Message's `from` field, which is renamed to `from_user` (because `from` is a Python reserved token). Thus, attributes such as `message_id` can be accessed directly with `message.message_id`. Note that `message.chat` can be either an instance of `User` or `GroupChat` (see [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)).
|
||||
|
||||
The Message object also has a `content_type`attribute, which defines the type of the Message. `content_type` can be one of the following strings:
|
||||
The Message object also has a `content_type`attribute, which defines the type of the Message. `content_type` can be one of the following strings:
|
||||
'text', 'audio', 'document', 'photo', 'sticker', 'video', 'location', 'contact', 'new_chat_participant', 'left_chat_participant', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created'.
|
||||
|
||||
### Methods
|
||||
@ -208,7 +208,7 @@ tb.polling(none_stop=False, interval=0, block=True)
|
||||
user = tb.get_me()
|
||||
|
||||
# setWebhook
|
||||
tb.set_webhook(url="http://example.com", cert=open('mycert.pem'))
|
||||
tb.set_webhook(url="http://example.com", certificate=open('mycert.pem'))
|
||||
# unset webhook
|
||||
tb.remove_webhook()
|
||||
|
||||
@ -373,8 +373,10 @@ bot.set_update_listener(handle_messages)
|
||||
bot.polling()
|
||||
```
|
||||
|
||||
### Using web hooks
|
||||
If you prefer using web hooks to the getUpdates method, you can use the `process_new_messages(messages)` function in TeleBot to make it process the messages that you supply. It takes a list of Message objects. This function is still incubating.
|
||||
### Using webhooks
|
||||
When using webhooks telegram sends one Update per call, for processing it you should call process_new_messages([update.message]) when you recieve it.
|
||||
|
||||
There are some examples using webhooks in the *examples/webhook_examples* directory.
|
||||
|
||||
### Logging
|
||||
|
||||
@ -423,4 +425,4 @@ We now have a Telegram Channel as well! Keep yourself up to date with API change
|
||||
|
||||
## 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.
|
||||
Want to have your bot listed here? Send a Telegram message to @eternnoir or @pevdh.
|
||||
|
100
README.rst
100
README.rst
@ -52,6 +52,7 @@ API <https://core.telegram.org/bots/api>`__.
|
||||
|
||||
- `The Telegram Chat Group <#the-telegram-chat-group>`__
|
||||
- `More examples <#more-examples>`__
|
||||
- `Bots using this API <#bots-using-this-api>`__
|
||||
|
||||
Getting started.
|
||||
================
|
||||
@ -213,9 +214,39 @@ 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):
|
||||
|
||||
.. code:: python
|
||||
|
||||
@bot.message_handler(filters)
|
||||
def function_name(message):
|
||||
bot.reply_to(message, "This is a message handler")
|
||||
|
||||
``function_name`` is not bound to any restrictions. Any function name is
|
||||
permitted with message handlers. The function must accept at most one
|
||||
argument, which will be the message that the function must handle.
|
||||
``filters`` is a list of keyword arguments. A filter is declared in the
|
||||
following manner: ``name=argument``. One handler may have multiple
|
||||
filters. TeleBot supports the following filters:
|
||||
|
||||
+------------------+---------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| name | argument(s) | Condition |
|
||||
+==================+=============================================+=================================================================================================================================================================================+
|
||||
| content\_types | list of strings (default ``['text']``) | ``True`` if message.content\_type is in the list of strings. |
|
||||
+------------------+---------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| regexp | a regular expression as a string | ``True`` if ``re.search(regexp_arg)`` returns ``True`` and ``message.content_type == 'text'`` (See `Python Regular Expressions <https://docs.python.org/2/library/re.html>`__ |
|
||||
+------------------+---------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| commands | list of strings | ``True`` if ``message.content_type == 'text'`` and ``message.text`` starts with a command that is in the list of strings. |
|
||||
+------------------+---------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| func | a function (lambda or function reference) | ``True`` if the lambda or function reference returns ``True`` |
|
||||
+------------------+---------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Here are some examples of using the filters and message handlers:
|
||||
|
||||
.. code:: python
|
||||
|
||||
@ -250,8 +281,15 @@ examples illustrate the possibilities of message handlers:
|
||||
def handle_text_doc(message)
|
||||
pass
|
||||
|
||||
*Note: all handlers are tested in the order in which they were declared*
|
||||
#### TeleBot
|
||||
# Handlers can be stacked to create a function which will be called if either message_handler is eligible
|
||||
# This handler will be called if the message starts with '/hello' OR is some emoji
|
||||
@bot.message_handler(commands=['hello'])
|
||||
@bot.message_handler(func=lambda msg: msg.text.encode("utf-8") == SOME_FANCY_EMOJI)
|
||||
def send_something(message):
|
||||
pass
|
||||
|
||||
**Important: all handlers are tested in the order in which they were
|
||||
declared** #### TeleBot
|
||||
|
||||
.. code:: python
|
||||
|
||||
@ -270,6 +308,11 @@ examples illustrate the possibilities of message handlers:
|
||||
# getMe
|
||||
user = tb.get_me()
|
||||
|
||||
# setWebhook
|
||||
tb.set_webhook(url="http://example.com", certificate=open('mycert.pem'))
|
||||
# unset webhook
|
||||
tb.remove_webhook()
|
||||
|
||||
# getUpdates
|
||||
updates = tb.get_updates()
|
||||
updates = tb.get_updates(1234,100,20) #get_Updates(offset, limit, timeout):
|
||||
@ -322,6 +365,14 @@ examples illustrate the possibilities of message handlers:
|
||||
# 'record_audio', 'upload_audio', 'upload_document' or 'find_location'.
|
||||
tb.send_chat_action(chat_id, action_string)
|
||||
|
||||
# getFile
|
||||
# Downloading a file is straightforward
|
||||
# Returns a File object
|
||||
import requests
|
||||
file_info = tb.get_file(file_id)
|
||||
|
||||
file = requests.get('https://api.telegram.org/file/bot{0}/{1}'.format(API_TOKEN, file_info.file_path))
|
||||
|
||||
Reply markup
|
||||
~~~~~~~~~~~~
|
||||
|
||||
@ -465,29 +516,31 @@ function as a listener to TeleBot. Example:
|
||||
bot.set_update_listener(handle_messages)
|
||||
bot.polling()
|
||||
|
||||
Using web hooks
|
||||
---------------
|
||||
Using webhooks
|
||||
--------------
|
||||
|
||||
If you prefer using web hooks to the getUpdates method, you can use the
|
||||
``process_new_messages(messages)`` function in TeleBot to make it
|
||||
process the messages that you supply. It takes a list of Message
|
||||
objects. This function is still incubating.
|
||||
When using webhooks telegram sends one Update per call, for processing
|
||||
it you should call process\_new\_messages([update.message]) when you
|
||||
recieve it.
|
||||
|
||||
There are some examples using webhooks in the
|
||||
*examples/webhook\_examples* directory.
|
||||
|
||||
Logging
|
||||
-------
|
||||
|
||||
You can use the Telebot module logger to log debug info about Telebot.
|
||||
Use ``telebot.logger`` to get the logger of the TeleBot module.
|
||||
Use ``telebot.logger`` to get the logger of the TeleBot module. It is
|
||||
possible to add custom logging Handlers to the logger. Refer to the
|
||||
`Python logging module
|
||||
page <https://docs.python.org/2/library/logging.html>`__ for more info.
|
||||
|
||||
.. code:: python
|
||||
|
||||
import logging
|
||||
|
||||
logger = telebot.logger
|
||||
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.
|
||||
======
|
||||
@ -513,6 +566,8 @@ Get help. Discuss. Chat.
|
||||
|
||||
Join the `pyTelegramBotAPI Telegram Chat
|
||||
Group <https://telegram.me/joinchat/067e22c60035523fda8f6025ee87e30b>`__.
|
||||
We now have a Telegram Channel as well! Keep yourself up to date with
|
||||
API changes, and `join it <https://telegram.me/pytelegrambotapi>`__.
|
||||
|
||||
More examples
|
||||
=============
|
||||
@ -524,5 +579,14 @@ More examples
|
||||
- `next\_step\_handler
|
||||
Example <https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/step_example.py>`__
|
||||
|
||||
Bots using this API
|
||||
===================
|
||||
|
||||
- `SiteAlert bot <https://telegram.me/SiteAlert_bot>`__
|
||||
(`source <https://github.com/ilteoood/SiteAlert-Python>`__) by
|
||||
*ilteoood* - Monitors websites and sends a notification on changes
|
||||
Want to have your bot listed here? Send a Telegram message to
|
||||
@eternnoir or @pevdh.
|
||||
|
||||
.. |Build Status| image:: https://travis-ci.org/eternnoir/pyTelegramBotAPI.svg?branch=master
|
||||
:target: https://travis-ci.org/eternnoir/pyTelegramBotAPI
|
||||
|
36
examples/webhook_examples/README.md
Normal file
36
examples/webhook_examples/README.md
Normal file
@ -0,0 +1,36 @@
|
||||
# Webhook examples using pyTelegramBotAPI
|
||||
|
||||
There are 3 examples in this directory using different libraries:
|
||||
|
||||
* **Python (CPython):** *webhook_cpython_echo_bot.py*
|
||||
* **Pros:**
|
||||
* Official python libraries, it works out of the box (doesn't require to
|
||||
install anything).
|
||||
* Works with Python 2 and Python 3 (need to be converted with 2to3).
|
||||
* **Cons:**
|
||||
* Ugly code.
|
||||
* Many things to handle yourself, this can lead to errors.
|
||||
* Not powerful, do the trick but the performance is low.
|
||||
|
||||
* **CherryPy (3.8.0):** *webhook_cherrypy_echo_bot.py*
|
||||
* **Pros:**
|
||||
* It's a web application framework, cleaner code, uses objects for defining
|
||||
the web application.
|
||||
* Very good performance.
|
||||
* The project seems to be active, latest version is recent.
|
||||
* Works with Python 2 and Python 3.
|
||||
* **Cons:**
|
||||
* Some things are not very intuitive, reading the doc is a must.
|
||||
|
||||
* **Flask (0.10.1):** *webhook_flask_echo_bot.py*
|
||||
* **Pros:**
|
||||
* It's a web application framework, cleaner code, uses decorator which can
|
||||
be nice.
|
||||
* Good performance.
|
||||
* It's intuitive if you know how web application works.
|
||||
* **Cons:**
|
||||
* The project seems not to be very active, latest version dates 2013.
|
||||
* They don't recommend to use it with Python 3, but may work.
|
||||
* May be a oversized for just handling webhook petitions.
|
||||
|
||||
*Latest update of this document: 2015-10-06*
|
85
examples/webhook_examples/webhook_cherrypy_echo_bot.py
Normal file
85
examples/webhook_examples/webhook_cherrypy_echo_bot.py
Normal file
@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This is a simple echo bot using decorators and webhook with CherryPy
|
||||
# It echoes any incoming text messages and does not use the polling method.
|
||||
|
||||
import cherrypy
|
||||
import telebot
|
||||
import logging
|
||||
|
||||
|
||||
API_TOKEN = '<api_token>'
|
||||
|
||||
WEBHOOK_HOST = '<ip/host where the bot is running>'
|
||||
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
|
||||
WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr
|
||||
|
||||
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
|
||||
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
|
||||
|
||||
# Quick'n'dirty SSL certificate generation:
|
||||
#
|
||||
# openssl genrsa -out webhook_pkey.pem 2048
|
||||
# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
|
||||
#
|
||||
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
|
||||
# with the same value in you put in WEBHOOK_HOST
|
||||
|
||||
WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT)
|
||||
WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN)
|
||||
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.INFO)
|
||||
|
||||
bot = telebot.TeleBot(API_TOKEN)
|
||||
|
||||
|
||||
# WebhookServer, process webhook calls
|
||||
class WebhookServer(object):
|
||||
@cherrypy.expose
|
||||
def index(self):
|
||||
if 'content-length' in cherrypy.request.headers and \
|
||||
'content-type' in cherrypy.request.headers and \
|
||||
cherrypy.request.headers['content-type'] == 'application/json':
|
||||
length = int(cherrypy.request.headers['content-length'])
|
||||
json_string = cherrypy.request.body.read(length)
|
||||
update = telebot.types.Update.de_json(json_string)
|
||||
bot.process_new_messages([update.message])
|
||||
return ''
|
||||
else:
|
||||
raise cherrypy.HTTPError(403)
|
||||
|
||||
|
||||
# Handle '/start' and '/help'
|
||||
@bot.message_handler(commands=['help', 'start'])
|
||||
def send_welcome(message):
|
||||
bot.reply_to(message,
|
||||
("Hi there, I am EchoBot.\n"
|
||||
"I am here to echo your kind words back to you."))
|
||||
|
||||
|
||||
# Handle all other messages
|
||||
@bot.message_handler(func=lambda message: True, content_types=['text'])
|
||||
def echo_message(message):
|
||||
bot.reply_to(message, message.text)
|
||||
|
||||
|
||||
# Remove webhook, it fails sometimes the set if there is a previous webhook
|
||||
bot.remove_webhook()
|
||||
|
||||
# Set webhook
|
||||
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
|
||||
certificate=open(WEBHOOK_SSL_CERT, 'r'))
|
||||
|
||||
# Start cherrypy server
|
||||
cherrypy.config.update({
|
||||
'server.socket_host': WEBHOOK_LISTEN,
|
||||
'server.socket_port': WEBHOOK_PORT,
|
||||
'server.ssl_module': 'builtin',
|
||||
'server.ssl_certificate': WEBHOOK_SSL_CERT,
|
||||
'server.ssl_private_key': WEBHOOK_SSL_PRIV
|
||||
})
|
||||
|
||||
cherrypy.quickstart(WebhookServer(), WEBHOOK_URL_PATH, {'/': {}})
|
99
examples/webhook_examples/webhook_cpython_echo_bot.py
Normal file
99
examples/webhook_examples/webhook_cpython_echo_bot.py
Normal file
@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This is a simple echo bot using decorators and webhook with BaseHTTPServer
|
||||
# It echoes any incoming text messages and does not use the polling method.
|
||||
|
||||
import BaseHTTPServer
|
||||
import ssl
|
||||
import telebot
|
||||
import logging
|
||||
|
||||
|
||||
API_TOKEN = '<api_token>'
|
||||
|
||||
WEBHOOK_HOST = '<ip/host where the bot is running>'
|
||||
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
|
||||
WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr
|
||||
|
||||
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
|
||||
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
|
||||
|
||||
# Quick'n'dirty SSL certificate generation:
|
||||
#
|
||||
# openssl genrsa -out webhook_pkey.pem 2048
|
||||
# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
|
||||
#
|
||||
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
|
||||
# with the same value in you put in WEBHOOK_HOST
|
||||
|
||||
WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT)
|
||||
WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN)
|
||||
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.INFO)
|
||||
|
||||
bot = telebot.TeleBot(API_TOKEN)
|
||||
|
||||
|
||||
# WebhookHandler, process webhook calls
|
||||
class WebhookHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
server_version = "WebhookHandler/1.0"
|
||||
|
||||
def do_HEAD(self):
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
|
||||
def do_GET(self):
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
|
||||
def do_POST(self):
|
||||
if self.path == WEBHOOK_URL_PATH and \
|
||||
'content-type' in self.headers and \
|
||||
'content-length' in self.headers and \
|
||||
self.headers['content-type'] == 'application/json':
|
||||
json_string = self.rfile.read(int(self.headers['content-length']))
|
||||
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
|
||||
update = telebot.types.Update.de_json(json_string)
|
||||
bot.process_new_messages([update.message])
|
||||
else:
|
||||
self.send_error(403)
|
||||
self.end_headers()
|
||||
|
||||
|
||||
# Handle '/start' and '/help'
|
||||
@bot.message_handler(commands=['help', 'start'])
|
||||
def send_welcome(message):
|
||||
bot.reply_to(message,
|
||||
("Hi there, I am EchoBot.\n"
|
||||
"I am here to echo your kind words back to you."))
|
||||
|
||||
|
||||
# Handle all other messages
|
||||
@bot.message_handler(func=lambda message: True, content_types=['text'])
|
||||
def echo_message(message):
|
||||
bot.reply_to(message, message.text)
|
||||
|
||||
|
||||
# Remove webhook, it fails sometimes the set if there is a previous webhook
|
||||
bot.remove_webhook()
|
||||
|
||||
# Set webhook
|
||||
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
|
||||
certificate=open(WEBHOOK_SSL_CERT, 'r'))
|
||||
|
||||
# Start server
|
||||
httpd = BaseHTTPServer.HTTPServer((WEBHOOK_LISTEN, WEBHOOK_PORT),
|
||||
WebhookHandler)
|
||||
|
||||
httpd.socket = ssl.wrap_socket(httpd.socket,
|
||||
certfile=WEBHOOK_SSL_CERT,
|
||||
keyfile=WEBHOOK_SSL_PRIV,
|
||||
server_side=True)
|
||||
|
||||
httpd.serve_forever()
|
84
examples/webhook_examples/webhook_flask_echo_bot.py
Normal file
84
examples/webhook_examples/webhook_flask_echo_bot.py
Normal file
@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This is a simple echo bot using decorators and webhook with flask
|
||||
# It echoes any incoming text messages and does not use the polling method.
|
||||
|
||||
import flask
|
||||
import telebot
|
||||
import logging
|
||||
|
||||
|
||||
API_TOKEN = '<api_token>'
|
||||
|
||||
WEBHOOK_HOST = '<ip/host where the bot is running>'
|
||||
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
|
||||
WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr
|
||||
|
||||
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
|
||||
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
|
||||
|
||||
# Quick'n'dirty SSL certificate generation:
|
||||
#
|
||||
# openssl genrsa -out webhook_pkey.pem 2048
|
||||
# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
|
||||
#
|
||||
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
|
||||
# with the same value in you put in WEBHOOK_HOST
|
||||
|
||||
WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT)
|
||||
WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN)
|
||||
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.INFO)
|
||||
|
||||
bot = telebot.TeleBot(API_TOKEN)
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
|
||||
# Empty webserver index, return nothing, just http 200
|
||||
@app.route('/', methods=['GET', 'HEAD'])
|
||||
def index():
|
||||
return ''
|
||||
|
||||
|
||||
# Process webhook calls
|
||||
@app.route(WEBHOOK_URL_PATH, methods=['POST'])
|
||||
def webhook():
|
||||
if flask.request.headers.get('content-type') == 'application/json':
|
||||
json_string = flask.request.get_data()
|
||||
update = telebot.types.Update.de_json(json_string)
|
||||
bot.process_new_messages([update.message])
|
||||
return ''
|
||||
else:
|
||||
flask.abort(403)
|
||||
|
||||
|
||||
# Handle '/start' and '/help'
|
||||
@bot.message_handler(commands=['help', 'start'])
|
||||
def send_welcome(message):
|
||||
bot.reply_to(message,
|
||||
("Hi there, I am EchoBot.\n"
|
||||
"I am here to echo your kind words back to you."))
|
||||
|
||||
|
||||
# Handle all other messages
|
||||
@bot.message_handler(func=lambda message: True, content_types=['text'])
|
||||
def echo_message(message):
|
||||
bot.reply_to(message, message.text)
|
||||
|
||||
|
||||
# Remove webhook, it fails sometimes the set if there is a previous webhook
|
||||
bot.remove_webhook()
|
||||
|
||||
# Set webhook
|
||||
bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH,
|
||||
certificate=open(WEBHOOK_SSL_CERT, 'r'))
|
||||
|
||||
# Start flask server
|
||||
app.run(host=WEBHOOK_LISTEN,
|
||||
port=WEBHOOK_PORT,
|
||||
ssl_context=(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV),
|
||||
debug=True)
|
@ -115,7 +115,7 @@ class TeleBot:
|
||||
for listener in self.update_listener:
|
||||
self.__exec_task(listener, new_messages)
|
||||
|
||||
def polling(self, none_stop=False, interval=0, timeout=3):
|
||||
def polling(self, none_stop=False, interval=0, timeout=20):
|
||||
"""
|
||||
This function creates a new Thread that calls an internal __retrieve_updates function.
|
||||
This allows the bot to retrieve Updates automagically and notify listeners and message handlers accordingly.
|
||||
@ -149,8 +149,7 @@ class TeleBot:
|
||||
try:
|
||||
polling_thread.put(self.__retrieve_updates, timeout)
|
||||
|
||||
while not or_event.is_set():
|
||||
time.sleep(.05) # wait for polling thread finish, polling thread error or thread pool error
|
||||
or_event.wait() # wait for polling thread finish, polling thread error or thread pool error
|
||||
|
||||
polling_thread.raise_exceptions()
|
||||
self.worker_pool.raise_exceptions()
|
||||
|
@ -43,14 +43,14 @@ def _check_result(method_name, result):
|
||||
"""
|
||||
if result.status_code != 200:
|
||||
msg = 'The server returned HTTP {0} {1}. Response body:\n[{2}]'\
|
||||
.format(result.status_code, result.reason, result.text)
|
||||
.format(result.status_code, result.reason, result.text.encode('utf8'))
|
||||
raise ApiException(msg, method_name, result)
|
||||
|
||||
try:
|
||||
result_json = result.json()
|
||||
except:
|
||||
msg = 'The server returned an invalid JSON response. Response body:\n[{0}]'\
|
||||
.format(result.text)
|
||||
.format(result.text.encode('utf8'))
|
||||
raise ApiException(msg, method_name, result)
|
||||
|
||||
if not result_json['ok']:
|
||||
|
@ -29,6 +29,7 @@ class JsonSerializable:
|
||||
Subclasses of this class are guaranteed to be able to be converted to JSON format.
|
||||
All subclasses of this class must override to_json.
|
||||
"""
|
||||
|
||||
def to_json(self):
|
||||
"""
|
||||
Returns a JSON string representation of this class.
|
||||
@ -44,6 +45,7 @@ class JsonDeserializable:
|
||||
Subclasses of this class are guaranteed to be able to be created from a json-style dict or json formatted string.
|
||||
All subclasses of this class must override de_json.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, json_type):
|
||||
"""
|
||||
@ -71,7 +73,7 @@ class JsonDeserializable:
|
||||
|
||||
def __str__(self):
|
||||
d = {}
|
||||
for x, y in self.__dict__.iteritems():
|
||||
for x, y in six.iteritems(self.__dict__):
|
||||
if hasattr(y, '__dict__'):
|
||||
d[x] = y.__dict__
|
||||
else:
|
||||
@ -79,6 +81,7 @@ class JsonDeserializable:
|
||||
|
||||
return six.text_type(d)
|
||||
|
||||
|
||||
class Update(JsonDeserializable):
|
||||
@classmethod
|
||||
def de_json(cls, json_type):
|
||||
@ -91,6 +94,7 @@ class Update(JsonDeserializable):
|
||||
self.update_id = update_id
|
||||
self.message = message
|
||||
|
||||
|
||||
class User(JsonDeserializable):
|
||||
@classmethod
|
||||
def de_json(cls, json_string):
|
||||
@ -125,13 +129,44 @@ class GroupChat(JsonDeserializable):
|
||||
self.title = title
|
||||
|
||||
|
||||
class Chat(JsonDeserializable):
|
||||
@classmethod
|
||||
def de_json(cls, json_string):
|
||||
obj = cls.check_json(json_string)
|
||||
id = obj['id']
|
||||
type = obj['type']
|
||||
title = None
|
||||
username = None
|
||||
first_name = None
|
||||
last_name = None
|
||||
if 'title' in obj:
|
||||
title = obj['title']
|
||||
if 'username' in obj:
|
||||
username = obj['username']
|
||||
if 'first_name'in obj:
|
||||
first_name = obj['first_name']
|
||||
if 'last_name' in obj:
|
||||
last_name = obj['last_name']
|
||||
return Chat(id, type, title, username, first_name, last_name)
|
||||
|
||||
def __init__(self, id, type, title=None, username=None, first_name=None, last_name=None):
|
||||
self.type = type
|
||||
self.last_name = last_name
|
||||
self.first_name = first_name
|
||||
self.username = username
|
||||
self.id = id
|
||||
self.title = title
|
||||
|
||||
|
||||
class Message(JsonDeserializable):
|
||||
@classmethod
|
||||
def de_json(cls, json_string):
|
||||
obj = cls.check_json(json_string)
|
||||
message_id = obj['message_id']
|
||||
from_user = User.de_json(obj['from'])
|
||||
chat = Message.parse_chat(obj['chat'])
|
||||
from_user = None
|
||||
if 'from' in obj:
|
||||
from_user = User.de_json(obj['from'])
|
||||
chat = Chat.de_json(obj['chat'])
|
||||
date = obj['date']
|
||||
content_type = None
|
||||
opts = {}
|
||||
@ -409,8 +444,8 @@ class UserProfilePhotos(JsonDeserializable):
|
||||
self.total_count = total_count
|
||||
self.photos = photos
|
||||
|
||||
class File(JsonDeserializable):
|
||||
|
||||
class File(JsonDeserializable):
|
||||
@classmethod
|
||||
def de_json(cls, json_type):
|
||||
obj = cls.check_json(json_type)
|
||||
|
@ -203,7 +203,6 @@ def orify(e, changed_callback):
|
||||
e.set = lambda: or_set(e)
|
||||
e.clear = lambda: or_clear(e)
|
||||
|
||||
|
||||
def OrEvent(*events):
|
||||
or_event = threading.Event()
|
||||
def changed():
|
||||
@ -212,7 +211,14 @@ def OrEvent(*events):
|
||||
or_event.set()
|
||||
else:
|
||||
or_event.clear()
|
||||
|
||||
def busy_wait():
|
||||
while not or_event.is_set():
|
||||
or_event._wait(3)
|
||||
|
||||
for e in events:
|
||||
orify(e, changed)
|
||||
or_event._wait = or_event.wait
|
||||
or_event.wait = busy_wait
|
||||
changed()
|
||||
return or_event
|
||||
|
@ -101,7 +101,6 @@ class TestTeleBot:
|
||||
ret_msg = tb.send_message(CHAT_ID, markdown, parse_mode="Markdown")
|
||||
assert ret_msg.message_id
|
||||
|
||||
|
||||
def test_send_file(self):
|
||||
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
@ -204,6 +203,13 @@ class TestTeleBot:
|
||||
assert int(ret_msg.location.longitude) == int(lon)
|
||||
assert int(ret_msg.location.latitude) == int(lat)
|
||||
|
||||
def test_Chat(self):
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
me = tb.get_me()
|
||||
msg = tb.send_message(CHAT_ID, 'Test')
|
||||
assert me.id == msg.from_user.id
|
||||
assert msg.chat.id == int(CHAT_ID)
|
||||
|
||||
def create_text_message(self, text):
|
||||
params = {'text': text}
|
||||
chat = types.User(11, 'test')
|
||||
@ -220,4 +226,3 @@ class TestTeleBot:
|
||||
def test_not_string(self):
|
||||
i1 = 10
|
||||
assert not util.is_string(i1)
|
||||
|
||||
|
@ -12,13 +12,13 @@ def test_json_user():
|
||||
|
||||
|
||||
def test_json_message():
|
||||
jsonstring = r'{"message_id":1,"from":{"id":108929734,"first_name":"Frank","last_name":"Wang","username":"eternnoir"},"chat":{"id":108929734,"first_name":"Frank","last_name":"Wang","username":"eternnoir"},"date":1435296025,"text":"HIHI"}'
|
||||
jsonstring = r'{"message_id":1,"from":{"id":108929734,"first_name":"Frank","last_name":"Wang","username":"eternnoir"},"chat":{"id":1734,"first_name":"F","type":"private","last_name":"Wa","username":"oir"},"date":1435296025,"text":"HIHI"}'
|
||||
msg = types.Message.de_json(jsonstring)
|
||||
assert msg.text == 'HIHI'
|
||||
|
||||
|
||||
def test_json_message_group():
|
||||
json_string = r'{"message_id":10,"from":{"id":12345,"first_name":"g","last_name":"G","username":"GG"},"chat":{"id":-866,"title":"\u4ea4"},"date":1435303157,"text":"HIHI"}'
|
||||
json_string = r'{"message_id":10,"from":{"id":12345,"first_name":"g","last_name":"G","username":"GG"},"chat":{"id":-866,"type":"private","title":"\u4ea4"},"date":1435303157,"text":"HIHI"}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.text == 'HIHI'
|
||||
assert len(msg.chat.title) != 0
|
||||
@ -39,7 +39,7 @@ def test_json_Document():
|
||||
|
||||
|
||||
def test_json_Message_Audio():
|
||||
json_string = r'{"message_id":131,"from":{"id":12775,"first_name":"dd","username":"dd"},"chat":{"id":10834,"first_name":"dd","last_name":"dd","username":"dd"},"date":1439978364,"audio":{"duration":1,"mime_type":"audio\/mpeg","title":"pyTelegram","performer":"eternnoir","file_id":"BQADBQADDH1JaB8-1KyWUss2-Ag","file_size":20096}}'
|
||||
json_string = r'{"message_id":131,"from":{"id":12775,"first_name":"dd","username":"dd"},"chat":{"id":10834,"first_name":"dd","type":"private","type":"private","last_name":"dd","username":"dd"},"date":1439978364,"audio":{"duration":1,"mime_type":"audio\/mpeg","title":"pyTelegram","performer":"eternnoir","file_id":"BQADBQADDH1JaB8-1KyWUss2-Ag","file_size":20096}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.audio.duration == 1
|
||||
assert msg.content_type == 'audio'
|
||||
@ -48,7 +48,7 @@ def test_json_Message_Audio():
|
||||
|
||||
|
||||
def test_json_Message_Sticker():
|
||||
json_string = r'{"message_id":98,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"date":1435479551,"sticker":{"width":550,"height":368,"thumb":{"file_id":"AAQFABPJLB0sAAQq17w-li3bzoIfAAIC","file_size":1822,"width":90,"height":60},"file_id":"BQADBQADNAIAAsYifgYdGJOa6bGAsQI","file_size":30320}}'
|
||||
json_string = r'{"message_id":98,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435479551,"sticker":{"width":550,"height":368,"thumb":{"file_id":"AAQFABPJLB0sAAQq17w-li3bzoIfAAIC","file_size":1822,"width":90,"height":60},"file_id":"BQADBQADNAIAAsYifgYdGJOa6bGAsQI","file_size":30320}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.sticker.height == 368
|
||||
assert msg.sticker.thumb.height == 60
|
||||
@ -56,7 +56,7 @@ def test_json_Message_Sticker():
|
||||
|
||||
|
||||
def test_json_Message_Sticker_without_thumb():
|
||||
json_string = r'{"message_id":98,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"date":1435479551,"sticker":{"width":550,"height":368,"file_id":"BQADBQADNAIAAsYifgYdGJOa6bGAsQI","file_size":30320}}'
|
||||
json_string = r'{"message_id":98,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435479551,"sticker":{"width":550,"height":368,"file_id":"BQADBQADNAIAAsYifgYdGJOa6bGAsQI","file_size":30320}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.sticker.height == 368
|
||||
assert msg.sticker.thumb == None
|
||||
@ -64,21 +64,21 @@ def test_json_Message_Sticker_without_thumb():
|
||||
|
||||
|
||||
def test_json_Message_Document():
|
||||
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10,"first_name":"Fd","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_size":446}}'
|
||||
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_size":446}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.document.file_name == 'Text File'
|
||||
assert msg.content_type == 'document'
|
||||
|
||||
|
||||
def test_json_Message_Photo():
|
||||
json_string = r'{"message_id":96,"from":{"id":109734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","last_name":"dd","username":"dd"},"date":1435478191,"photo":[{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":615,"width":90,"height":67},{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":10174,"width":320,"height":240},{"file_id":"dd-A_LsTIABFNx-FUOaEa_3AABAQABAg","file_size":53013,"width":759,"height":570}]}'
|
||||
json_string = r'{"message_id":96,"from":{"id":109734,"first_name":"Fd","last_name":"Wd","username":"dd"},"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"dd","username":"dd"},"date":1435478191,"photo":[{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":615,"width":90,"height":67},{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":10174,"width":320,"height":240},{"file_id":"dd-A_LsTIABFNx-FUOaEa_3AABAQABAg","file_size":53013,"width":759,"height":570}]}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert len(msg.photo) == 3
|
||||
assert msg.content_type == 'photo'
|
||||
|
||||
|
||||
def test_json_Message_Video():
|
||||
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_size":260699}}'
|
||||
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_size":260699}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.video
|
||||
assert msg.video.duration == 3
|
||||
@ -87,7 +87,7 @@ def test_json_Message_Video():
|
||||
|
||||
|
||||
def test_json_Message_Location():
|
||||
json_string = r'{"message_id":102,"from":{"id":108734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":1089734,"first_name":"dd","last_name":"dd","username":"dd"},"date":1535482469,"location":{"longitude":127.479471,"latitude":26.090577}}'
|
||||
json_string = r'{"message_id":102,"from":{"id":108734,"first_name":"dd","last_name":"dd","username":"dd"},"chat":{"id":1089734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1535482469,"location":{"longitude":127.479471,"latitude":26.090577}}'
|
||||
msg = types.Message.de_json(json_string)
|
||||
assert msg.location.latitude == 26.090577
|
||||
assert msg.content_type == 'location'
|
||||
@ -114,9 +114,16 @@ def test_json_voice():
|
||||
assert voice.file_size == 10481
|
||||
|
||||
def test_json_update():
|
||||
json_string = r'{"update_id":938203,"message":{"message_id":241,"from":{"id":9734,"first_name":"Fk","last_name":"Wg","username":"nir"},"chat":{"id":1111,"first_name":"Fk","last_name":"Wg","username":"oir"},"date":1441447009,"text":"HIHI"}}'
|
||||
json_string = r'{"update_id":938203,"message":{"message_id":241,"from":{"id":9734,"first_name":"Fk","last_name":"Wg","username":"nir"},"chat":{"id":1111,"first_name":"Fk","type":"private","last_name":"Wg","username":"oir"},"date":1441447009,"text":"HIHI"}}'
|
||||
update = types.Update.de_json(json_string)
|
||||
assert update.update_id == 938203
|
||||
assert update.message.message_id == 241
|
||||
assert update.message.from_user.id == 9734
|
||||
|
||||
def test_json_chat():
|
||||
json_string = r'{"id": -111111,"title": "Test Title","type": "group"}'
|
||||
chat = types.Chat.de_json(json_string)
|
||||
assert chat.id == -111111
|
||||
assert chat.type == 'group'
|
||||
assert chat.title == 'Test Title'
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user