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
@ -208,7 +208,7 @@ tb.polling(none_stop=False, interval=0, block=True)
|
|||||||
user = tb.get_me()
|
user = tb.get_me()
|
||||||
|
|
||||||
# setWebhook
|
# 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
|
# unset webhook
|
||||||
tb.remove_webhook()
|
tb.remove_webhook()
|
||||||
|
|
||||||
@ -374,7 +374,9 @@ bot.polling()
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Using webhooks
|
### 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
|
### Logging
|
||||||
|
|
||||||
|
98
README.rst
98
README.rst
@ -52,6 +52,7 @@ API <https://core.telegram.org/bots/api>`__.
|
|||||||
|
|
||||||
- `The Telegram Chat Group <#the-telegram-chat-group>`__
|
- `The Telegram Chat Group <#the-telegram-chat-group>`__
|
||||||
- `More examples <#more-examples>`__
|
- `More examples <#more-examples>`__
|
||||||
|
- `Bots using this API <#bots-using-this-api>`__
|
||||||
|
|
||||||
Getting started.
|
Getting started.
|
||||||
================
|
================
|
||||||
@ -213,9 +214,39 @@ Outlined below are some general use cases of the API.
|
|||||||
Message handlers
|
Message handlers
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
A message handler is a function which is decorated with the
|
A message handler is a function that is decorated with the
|
||||||
``message_handler`` decorator of a TeleBot instance. The following
|
``message_handler`` decorator of a TeleBot instance. Message handlers
|
||||||
examples illustrate the possibilities of 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
|
.. code:: python
|
||||||
|
|
||||||
@ -250,8 +281,15 @@ examples illustrate the possibilities of message handlers:
|
|||||||
def handle_text_doc(message)
|
def handle_text_doc(message)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
*Note: all handlers are tested in the order in which they were declared*
|
# Handlers can be stacked to create a function which will be called if either message_handler is eligible
|
||||||
#### TeleBot
|
# 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
|
.. code:: python
|
||||||
|
|
||||||
@ -270,6 +308,11 @@ examples illustrate the possibilities of message handlers:
|
|||||||
# getMe
|
# getMe
|
||||||
user = tb.get_me()
|
user = tb.get_me()
|
||||||
|
|
||||||
|
# setWebhook
|
||||||
|
tb.set_webhook(url="http://example.com", certificate=open('mycert.pem'))
|
||||||
|
# unset webhook
|
||||||
|
tb.remove_webhook()
|
||||||
|
|
||||||
# getUpdates
|
# getUpdates
|
||||||
updates = tb.get_updates()
|
updates = tb.get_updates()
|
||||||
updates = tb.get_updates(1234,100,20) #get_Updates(offset, limit, timeout):
|
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'.
|
# 'record_audio', 'upload_audio', 'upload_document' or 'find_location'.
|
||||||
tb.send_chat_action(chat_id, action_string)
|
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
|
Reply markup
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -466,28 +517,30 @@ function as a listener to TeleBot. Example:
|
|||||||
bot.polling()
|
bot.polling()
|
||||||
|
|
||||||
Using webhooks
|
Using webhooks
|
||||||
---------------
|
--------------
|
||||||
|
|
||||||
If you prefer using web hooks to the getUpdates method, you can use the
|
When using webhooks telegram sends one Update per call, for processing
|
||||||
``process_new_messages(messages)`` function in TeleBot to make it
|
it you should call process\_new\_messages([update.message]) when you
|
||||||
process the messages that you supply. It takes a list of Message
|
recieve it.
|
||||||
objects. This function is still incubating.
|
|
||||||
|
There are some examples using webhooks in the
|
||||||
|
*examples/webhook\_examples* directory.
|
||||||
|
|
||||||
Logging
|
Logging
|
||||||
-------
|
-------
|
||||||
|
|
||||||
You can use the Telebot module logger to log debug info about Telebot.
|
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
|
.. code:: python
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
logger = telebot.logger
|
logger = telebot.logger
|
||||||
formatter = logging.Formatter('[%(asctime)s] %(thread)d {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
|
telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console.
|
||||||
'%m-%d %H:%M:%S')
|
|
||||||
ch = logging.StreamHandler(sys.stdout)
|
|
||||||
logger.addHandler(ch)
|
|
||||||
logger.setLevel(logging.DEBUG) # or use logging.INFO
|
|
||||||
ch.setFormatter(formatter)
|
|
||||||
|
|
||||||
F.A.Q.
|
F.A.Q.
|
||||||
======
|
======
|
||||||
@ -513,6 +566,8 @@ Get help. Discuss. Chat.
|
|||||||
|
|
||||||
Join the `pyTelegramBotAPI Telegram Chat
|
Join the `pyTelegramBotAPI Telegram Chat
|
||||||
Group <https://telegram.me/joinchat/067e22c60035523fda8f6025ee87e30b>`__.
|
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
|
More examples
|
||||||
=============
|
=============
|
||||||
@ -524,5 +579,14 @@ More examples
|
|||||||
- `next\_step\_handler
|
- `next\_step\_handler
|
||||||
Example <https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/step_example.py>`__
|
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
|
.. |Build Status| image:: https://travis-ci.org/eternnoir/pyTelegramBotAPI.svg?branch=master
|
||||||
:target: https://travis-ci.org/eternnoir/pyTelegramBotAPI
|
: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:
|
for listener in self.update_listener:
|
||||||
self.__exec_task(listener, new_messages)
|
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 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.
|
This allows the bot to retrieve Updates automagically and notify listeners and message handlers accordingly.
|
||||||
@ -149,8 +149,7 @@ class TeleBot:
|
|||||||
try:
|
try:
|
||||||
polling_thread.put(self.__retrieve_updates, timeout)
|
polling_thread.put(self.__retrieve_updates, timeout)
|
||||||
|
|
||||||
while not or_event.is_set():
|
or_event.wait() # wait for polling thread finish, polling thread error or thread pool error
|
||||||
time.sleep(.05) # wait for polling thread finish, polling thread error or thread pool error
|
|
||||||
|
|
||||||
polling_thread.raise_exceptions()
|
polling_thread.raise_exceptions()
|
||||||
self.worker_pool.raise_exceptions()
|
self.worker_pool.raise_exceptions()
|
||||||
|
@ -43,14 +43,14 @@ def _check_result(method_name, result):
|
|||||||
"""
|
"""
|
||||||
if result.status_code != 200:
|
if result.status_code != 200:
|
||||||
msg = 'The server returned HTTP {0} {1}. Response body:\n[{2}]'\
|
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)
|
raise ApiException(msg, method_name, result)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result_json = result.json()
|
result_json = result.json()
|
||||||
except:
|
except:
|
||||||
msg = 'The server returned an invalid JSON response. Response body:\n[{0}]'\
|
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)
|
raise ApiException(msg, method_name, result)
|
||||||
|
|
||||||
if not result_json['ok']:
|
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.
|
Subclasses of this class are guaranteed to be able to be converted to JSON format.
|
||||||
All subclasses of this class must override to_json.
|
All subclasses of this class must override to_json.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
"""
|
"""
|
||||||
Returns a JSON string representation of this class.
|
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.
|
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.
|
All subclasses of this class must override de_json.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def de_json(cls, json_type):
|
def de_json(cls, json_type):
|
||||||
"""
|
"""
|
||||||
@ -71,7 +73,7 @@ class JsonDeserializable:
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
d = {}
|
d = {}
|
||||||
for x, y in self.__dict__.iteritems():
|
for x, y in six.iteritems(self.__dict__):
|
||||||
if hasattr(y, '__dict__'):
|
if hasattr(y, '__dict__'):
|
||||||
d[x] = y.__dict__
|
d[x] = y.__dict__
|
||||||
else:
|
else:
|
||||||
@ -79,6 +81,7 @@ class JsonDeserializable:
|
|||||||
|
|
||||||
return six.text_type(d)
|
return six.text_type(d)
|
||||||
|
|
||||||
|
|
||||||
class Update(JsonDeserializable):
|
class Update(JsonDeserializable):
|
||||||
@classmethod
|
@classmethod
|
||||||
def de_json(cls, json_type):
|
def de_json(cls, json_type):
|
||||||
@ -91,6 +94,7 @@ class Update(JsonDeserializable):
|
|||||||
self.update_id = update_id
|
self.update_id = update_id
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
|
|
||||||
class User(JsonDeserializable):
|
class User(JsonDeserializable):
|
||||||
@classmethod
|
@classmethod
|
||||||
def de_json(cls, json_string):
|
def de_json(cls, json_string):
|
||||||
@ -125,13 +129,44 @@ class GroupChat(JsonDeserializable):
|
|||||||
self.title = title
|
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):
|
class Message(JsonDeserializable):
|
||||||
@classmethod
|
@classmethod
|
||||||
def de_json(cls, json_string):
|
def de_json(cls, json_string):
|
||||||
obj = cls.check_json(json_string)
|
obj = cls.check_json(json_string)
|
||||||
message_id = obj['message_id']
|
message_id = obj['message_id']
|
||||||
|
from_user = None
|
||||||
|
if 'from' in obj:
|
||||||
from_user = User.de_json(obj['from'])
|
from_user = User.de_json(obj['from'])
|
||||||
chat = Message.parse_chat(obj['chat'])
|
chat = Chat.de_json(obj['chat'])
|
||||||
date = obj['date']
|
date = obj['date']
|
||||||
content_type = None
|
content_type = None
|
||||||
opts = {}
|
opts = {}
|
||||||
@ -409,8 +444,8 @@ class UserProfilePhotos(JsonDeserializable):
|
|||||||
self.total_count = total_count
|
self.total_count = total_count
|
||||||
self.photos = photos
|
self.photos = photos
|
||||||
|
|
||||||
class File(JsonDeserializable):
|
|
||||||
|
|
||||||
|
class File(JsonDeserializable):
|
||||||
@classmethod
|
@classmethod
|
||||||
def de_json(cls, json_type):
|
def de_json(cls, json_type):
|
||||||
obj = cls.check_json(json_type)
|
obj = cls.check_json(json_type)
|
||||||
|
@ -203,7 +203,6 @@ def orify(e, changed_callback):
|
|||||||
e.set = lambda: or_set(e)
|
e.set = lambda: or_set(e)
|
||||||
e.clear = lambda: or_clear(e)
|
e.clear = lambda: or_clear(e)
|
||||||
|
|
||||||
|
|
||||||
def OrEvent(*events):
|
def OrEvent(*events):
|
||||||
or_event = threading.Event()
|
or_event = threading.Event()
|
||||||
def changed():
|
def changed():
|
||||||
@ -212,7 +211,14 @@ def OrEvent(*events):
|
|||||||
or_event.set()
|
or_event.set()
|
||||||
else:
|
else:
|
||||||
or_event.clear()
|
or_event.clear()
|
||||||
|
|
||||||
|
def busy_wait():
|
||||||
|
while not or_event.is_set():
|
||||||
|
or_event._wait(3)
|
||||||
|
|
||||||
for e in events:
|
for e in events:
|
||||||
orify(e, changed)
|
orify(e, changed)
|
||||||
|
or_event._wait = or_event.wait
|
||||||
|
or_event.wait = busy_wait
|
||||||
changed()
|
changed()
|
||||||
return or_event
|
return or_event
|
||||||
|
@ -101,7 +101,6 @@ class TestTeleBot:
|
|||||||
ret_msg = tb.send_message(CHAT_ID, markdown, parse_mode="Markdown")
|
ret_msg = tb.send_message(CHAT_ID, markdown, parse_mode="Markdown")
|
||||||
assert ret_msg.message_id
|
assert ret_msg.message_id
|
||||||
|
|
||||||
|
|
||||||
def test_send_file(self):
|
def test_send_file(self):
|
||||||
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
|
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
|
||||||
tb = telebot.TeleBot(TOKEN)
|
tb = telebot.TeleBot(TOKEN)
|
||||||
@ -204,6 +203,13 @@ class TestTeleBot:
|
|||||||
assert int(ret_msg.location.longitude) == int(lon)
|
assert int(ret_msg.location.longitude) == int(lon)
|
||||||
assert int(ret_msg.location.latitude) == int(lat)
|
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):
|
def create_text_message(self, text):
|
||||||
params = {'text': text}
|
params = {'text': text}
|
||||||
chat = types.User(11, 'test')
|
chat = types.User(11, 'test')
|
||||||
@ -220,4 +226,3 @@ class TestTeleBot:
|
|||||||
def test_not_string(self):
|
def test_not_string(self):
|
||||||
i1 = 10
|
i1 = 10
|
||||||
assert not util.is_string(i1)
|
assert not util.is_string(i1)
|
||||||
|
|
||||||
|
@ -12,13 +12,13 @@ def test_json_user():
|
|||||||
|
|
||||||
|
|
||||||
def test_json_message():
|
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)
|
msg = types.Message.de_json(jsonstring)
|
||||||
assert msg.text == 'HIHI'
|
assert msg.text == 'HIHI'
|
||||||
|
|
||||||
|
|
||||||
def test_json_message_group():
|
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)
|
msg = types.Message.de_json(json_string)
|
||||||
assert msg.text == 'HIHI'
|
assert msg.text == 'HIHI'
|
||||||
assert len(msg.chat.title) != 0
|
assert len(msg.chat.title) != 0
|
||||||
@ -39,7 +39,7 @@ def test_json_Document():
|
|||||||
|
|
||||||
|
|
||||||
def test_json_Message_Audio():
|
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)
|
msg = types.Message.de_json(json_string)
|
||||||
assert msg.audio.duration == 1
|
assert msg.audio.duration == 1
|
||||||
assert msg.content_type == 'audio'
|
assert msg.content_type == 'audio'
|
||||||
@ -48,7 +48,7 @@ def test_json_Message_Audio():
|
|||||||
|
|
||||||
|
|
||||||
def test_json_Message_Sticker():
|
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)
|
msg = types.Message.de_json(json_string)
|
||||||
assert msg.sticker.height == 368
|
assert msg.sticker.height == 368
|
||||||
assert msg.sticker.thumb.height == 60
|
assert msg.sticker.thumb.height == 60
|
||||||
@ -56,7 +56,7 @@ def test_json_Message_Sticker():
|
|||||||
|
|
||||||
|
|
||||||
def test_json_Message_Sticker_without_thumb():
|
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)
|
msg = types.Message.de_json(json_string)
|
||||||
assert msg.sticker.height == 368
|
assert msg.sticker.height == 368
|
||||||
assert msg.sticker.thumb == None
|
assert msg.sticker.thumb == None
|
||||||
@ -64,21 +64,21 @@ def test_json_Message_Sticker_without_thumb():
|
|||||||
|
|
||||||
|
|
||||||
def test_json_Message_Document():
|
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)
|
msg = types.Message.de_json(json_string)
|
||||||
assert msg.document.file_name == 'Text File'
|
assert msg.document.file_name == 'Text File'
|
||||||
assert msg.content_type == 'document'
|
assert msg.content_type == 'document'
|
||||||
|
|
||||||
|
|
||||||
def test_json_Message_Photo():
|
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)
|
msg = types.Message.de_json(json_string)
|
||||||
assert len(msg.photo) == 3
|
assert len(msg.photo) == 3
|
||||||
assert msg.content_type == 'photo'
|
assert msg.content_type == 'photo'
|
||||||
|
|
||||||
|
|
||||||
def test_json_Message_Video():
|
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)
|
msg = types.Message.de_json(json_string)
|
||||||
assert msg.video
|
assert msg.video
|
||||||
assert msg.video.duration == 3
|
assert msg.video.duration == 3
|
||||||
@ -87,7 +87,7 @@ def test_json_Message_Video():
|
|||||||
|
|
||||||
|
|
||||||
def test_json_Message_Location():
|
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)
|
msg = types.Message.de_json(json_string)
|
||||||
assert msg.location.latitude == 26.090577
|
assert msg.location.latitude == 26.090577
|
||||||
assert msg.content_type == 'location'
|
assert msg.content_type == 'location'
|
||||||
@ -114,9 +114,16 @@ def test_json_voice():
|
|||||||
assert voice.file_size == 10481
|
assert voice.file_size == 10481
|
||||||
|
|
||||||
def test_json_update():
|
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)
|
update = types.Update.de_json(json_string)
|
||||||
assert update.update_id == 938203
|
assert update.update_id == 938203
|
||||||
assert update.message.message_id == 241
|
assert update.message.message_id == 241
|
||||||
assert update.message.from_user.id == 9734
|
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