1
0
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:
eternnoir 2015-10-12 22:37:17 +08:00
commit 8e9837a587
12 changed files with 467 additions and 45 deletions

View File

@ -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

View File

@ -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

View 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*

View 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, {'/': {}})

View 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()

View 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)

View File

@ -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()

View File

@ -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']:

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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'