diff --git a/examples/deep_linking.py b/examples/deep_linking.py index 91fcb15..98df204 100644 --- a/examples/deep_linking.py +++ b/examples/deep_linking.py @@ -34,30 +34,35 @@ import telebot bot = telebot.TeleBot('TOKEN') + def extract_unique_code(text): # Extracts the unique_code from the sent /start command. return text.split()[1] if len(text.split()) > 1 else None + def in_storage(unique_code): # (pseudo-code) Should check if a unique code exists in storage return True + def get_username_from_storage(unique_code): # (pseudo-code) Does a query to the storage, retrieving the associated username # Should be replaced by a real database-lookup. return "ABC" if in_storage(unique_code) else None + def save_chat_id(chat_id, username): # (pseudo-code) Save the chat_id->username to storage # Should be replaced by a real database query. pass + @bot.message_handler(commands=['start']) def send_welcome(message): unique_code = extract_unique_code(message.text) - if unique_code: # if the '/start' command contains a unique_code + if unique_code: # if the '/start' command contains a unique_code username = get_username_from_storage(unique_code) - if username: # if the username exists in our database + if username: # if the username exists in our database save_chat_id(message.chat.id, username) reply = "Hello {0}, how are you?".format(username) else: @@ -66,4 +71,5 @@ def send_welcome(message): reply = "Please visit me via a provided URL from the website." bot.reply_to(message, reply) + bot.polling() diff --git a/examples/detailed_example/detailed_example.py b/examples/detailed_example/detailed_example.py index 83fcb67..f481832 100644 --- a/examples/detailed_example/detailed_example.py +++ b/examples/detailed_example/detailed_example.py @@ -13,10 +13,10 @@ knownUsers = [] # todo: save these in a file, userStep = {} # so they won't reset every time the bot restarts commands = { # command description used in the "help" command - 'start': 'Get used to the bot', - 'help': 'Gives you information about the available commands', - 'sendLongText': 'A test using the \'send_chat_action\' command', - 'getImage': 'A test using multi-stage messages, custom keyboard, and media sending' + 'start' : 'Get used to the bot', + 'help' : 'Gives you information about the available commands', + 'sendLongText': 'A test using the \'send_chat_action\' command', + 'getImage' : 'A test using multi-stage messages, custom keyboard, and media sending' } imageSelect = types.ReplyKeyboardMarkup(one_time_keyboard=True) # create the image selection keyboard @@ -129,4 +129,5 @@ def command_default(m): # this is the standard reply to a normal message bot.send_message(m.chat.id, "I don't understand \"" + m.text + "\"\nMaybe try the help page at /help") + bot.polling() diff --git a/examples/echo_bot.py b/examples/echo_bot.py index f88d3bf..b20f09d 100644 --- a/examples/echo_bot.py +++ b/examples/echo_bot.py @@ -7,6 +7,7 @@ API_TOKEN = '' bot = telebot.TeleBot(API_TOKEN) + # Handle '/start' and '/help' @bot.message_handler(commands=['help', 'start']) def send_welcome(message): @@ -21,4 +22,5 @@ I am here to echo your kind words back to you. Just say anything nice and I'll s def echo_message(message): bot.reply_to(message, message.text) + bot.polling() diff --git a/examples/step_example.py b/examples/step_example.py index fea047e..0fc17e5 100644 --- a/examples/step_example.py +++ b/examples/step_example.py @@ -83,5 +83,4 @@ bot.enable_save_next_step_handlers(delay=2) # WARNING It will work only if enable_save_next_step_handlers was called! bot.load_next_step_handlers() - bot.polling() diff --git a/examples/telebot_bot/telebot_bot.py b/examples/telebot_bot/telebot_bot.py index b599efe..ac6b63c 100644 --- a/examples/telebot_bot/telebot_bot.py +++ b/examples/telebot_bot/telebot_bot.py @@ -34,8 +34,10 @@ if "TELEBOT_BOT_TOKEN" not in os.environ or "GROUP_CHAT_ID" not in os.environ: bot = telebot.AsyncTeleBot(os.environ["TELEBOT_BOT_TOKEN"]) GROUP_CHAT_ID = int(os.environ["GROUP_CHAT_ID"]) + def is_api_group(chat_id): - return chat_id== GROUP_CHAT_ID + return chat_id == GROUP_CHAT_ID + @bot.message_handler(func=lambda m: True, content_types=['new_chat_participant']) def on_user_joins(message): @@ -51,6 +53,7 @@ def on_user_joins(message): bot.reply_to(message, text_messages['welcome'].format(name=name)) + @bot.message_handler(commands=['info', 'help']) def on_info(message): if not is_api_group(message.chat.id): @@ -59,21 +62,23 @@ def on_info(message): bot.reply_to(message, text_messages['info']) + @bot.message_handler(commands=["ping"]) def on_ping(message): bot.reply_to(message, "Still alive and kicking!") + @bot.message_handler(commands=['start']) def on_start(message): if not is_api_group(message.chat.id): bot.reply_to(message, text_messages['wrong_chat']) return + def listener(messages): for m in messages: print(str(m)) + bot.set_update_listener(listener) bot.polling() - - diff --git a/examples/webhook_examples/webhook_aiohttp_echo_bot.py b/examples/webhook_examples/webhook_aiohttp_echo_bot.py index c949b84..bbb7c6e 100644 --- a/examples/webhook_examples/webhook_aiohttp_echo_bot.py +++ b/examples/webhook_examples/webhook_aiohttp_echo_bot.py @@ -31,7 +31,6 @@ WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key WEBHOOK_URL_BASE = "https://{}:{}".format(WEBHOOK_HOST, WEBHOOK_PORT) WEBHOOK_URL_PATH = "/{}/".format(API_TOKEN) - logger = telebot.logger telebot.logger.setLevel(logging.INFO) @@ -50,6 +49,7 @@ async def handle(request): else: return web.Response(status=403) + app.router.add_post('/{token}/', handle) @@ -71,7 +71,7 @@ def echo_message(message): bot.remove_webhook() # Set webhook -bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH, +bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, certificate=open(WEBHOOK_SSL_CERT, 'r')) # Build ssl context diff --git a/examples/webhook_examples/webhook_cherrypy_echo_bot.py b/examples/webhook_examples/webhook_cherrypy_echo_bot.py index c679a01..7b46e78 100644 --- a/examples/webhook_examples/webhook_cherrypy_echo_bot.py +++ b/examples/webhook_examples/webhook_cherrypy_echo_bot.py @@ -30,7 +30,6 @@ WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT) WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN) - logger = telebot.logger telebot.logger.setLevel(logging.INFO) @@ -71,7 +70,7 @@ def echo_message(message): bot.remove_webhook() # Set webhook -bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH, +bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, certificate=open(WEBHOOK_SSL_CERT, 'r')) # Disable CherryPy requests log @@ -81,9 +80,9 @@ for handler in tuple(access_log.handlers): # Start cherrypy server cherrypy.config.update({ - 'server.socket_host': WEBHOOK_LISTEN, - 'server.socket_port': WEBHOOK_PORT, - 'server.ssl_module': 'builtin', + '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 }) diff --git a/examples/webhook_examples/webhook_cpython_echo_bot.py b/examples/webhook_examples/webhook_cpython_echo_bot.py index 639dcae..029f361 100644 --- a/examples/webhook_examples/webhook_cpython_echo_bot.py +++ b/examples/webhook_examples/webhook_cpython_echo_bot.py @@ -36,7 +36,6 @@ WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT) WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN) - logger = telebot.logger telebot.logger.setLevel(logging.INFO) @@ -90,12 +89,12 @@ def echo_message(message): bot.remove_webhook() # Set webhook -bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH, +bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, certificate=open(WEBHOOK_SSL_CERT, 'r')) # Start server httpd = HTTPServer((WEBHOOK_LISTEN, WEBHOOK_PORT), - WebhookHandler) + WebhookHandler) httpd.socket = ssl.wrap_socket(httpd.socket, certfile=WEBHOOK_SSL_CERT, diff --git a/examples/webhook_examples/webhook_flask_echo_bot.py b/examples/webhook_examples/webhook_flask_echo_bot.py index 2567cab..daa3995 100644 --- a/examples/webhook_examples/webhook_flask_echo_bot.py +++ b/examples/webhook_examples/webhook_flask_echo_bot.py @@ -31,7 +31,6 @@ WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT) WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN) - logger = telebot.logger telebot.logger.setLevel(logging.INFO) @@ -78,7 +77,7 @@ bot.remove_webhook() time.sleep(0.1) # Set webhook -bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH, +bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, certificate=open(WEBHOOK_SSL_CERT, 'r')) # Start flask server diff --git a/examples/webhook_examples/webhook_tornado_echo_bot.py b/examples/webhook_examples/webhook_tornado_echo_bot.py index c4c64b0..171d2d7 100644 --- a/examples/webhook_examples/webhook_tornado_echo_bot.py +++ b/examples/webhook_examples/webhook_tornado_echo_bot.py @@ -31,15 +31,18 @@ WEBHOOK_URL_BASE = "https://{0}:{1}/{2}".format(WEBHOOK_HOST, str(WEBHOOK_PORT), bot = telebot.TeleBot(API_TOKEN) + class Root(tornado.web.RequestHandler): def get(self): self.write("Hi! This is webhook example!") self.finish() + class webhook_serv(tornado.web.RequestHandler): def get(self): self.write("What are you doing here?") self.finish() + def post(self): if "Content-Length" in self.request.headers and \ "Content-Type" in self.request.headers and \ @@ -54,21 +57,26 @@ class webhook_serv(tornado.web.RequestHandler): else: self.write("What are you doing here?") self.finish() - + + tornado.options.define("port", default=WEBHOOK_PORT, help="run on the given port", type=int) is_closing = False + + def signal_handler(signum, frame): global is_closing print("Exiting...") is_closing = True + def try_exit(): global is_closing if is_closing: # clean up here tornado.ioloop.IOLoop.instance().stop() print("Exit success!") - + + # Handle '/start' and '/help' @bot.message_handler(commands=['help', 'start']) def send_welcome(message): @@ -76,6 +84,7 @@ def send_welcome(message): ("Hi there, I am EchoBot.\n" "I am here to echo your kind words back to you.")) + bot.remove_webhook() bot.set_webhook(url=WEBHOOK_URL_BASE, certificate=open(WEBHOOK_CERT, 'r')) @@ -88,9 +97,9 @@ application = tornado.web.Application([ ]) http_server = tornado.httpserver.HTTPServer(application, ssl_options={ - "certfile": WEBHOOK_CERT, - "keyfile": WEBHOOK_PKEY, - }) + "certfile": WEBHOOK_CERT, + "keyfile" : WEBHOOK_PKEY, +}) http_server.listen(tornado.options.options.port) tornado.ioloop.PeriodicCallback(try_exit, 100).start() tornado.ioloop.IOLoop.instance().start() diff --git a/telebot/__init__.py b/telebot/__init__.py index 95fa03a..52a4e5a 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -33,6 +33,7 @@ class Handler: """ Class for (next step|reply) handlers """ + def __init__(self, callback, *args, **kwargs): self.callback = callback self.args = args @@ -46,6 +47,7 @@ class Saver: """ Class for saving (next step|reply) handlers """ + def __init__(self, handlers, filename, delay): self.handlers = handlers self.filename = filename @@ -1303,12 +1305,11 @@ class TeleBot: if not was_poped: i += 1 - @staticmethod def _build_handler_dict(handler, **filters): return { 'function': handler, - 'filters': filters + 'filters' : filters } def message_handler(self, commands=None, regexp=None, func=None, content_types=['text'], **kwargs): @@ -1518,8 +1519,6 @@ class AsyncTeleBot(TeleBot): def load_reply_handlers(self, filename="./.handler-saves/reply.save", del_file_after_loading=True): return TeleBot.load_reply_handlers(self, filename, del_file_after_loading) - @util.async_dec() - @util.async_dec() def get_me(self): return TeleBot.get_me(self) diff --git a/telebot/types.py b/telebot/types.py index 884e3d4..06a1c44 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -457,11 +457,11 @@ class Message(JsonDeserializable): if not entities: return text _subs = { - "bold": "{text}", - "italic": "{text}", - "pre": "
{text}
", - "code": "{text}", - "url": "{text}", + "bold" : "{text}", + "italic" : "{text}", + "pre" : "
{text}
", + "code" : "{text}", + "url" : "{text}", "text_link": "{text}" } if hasattr(self, "custom_subs"): @@ -469,6 +469,7 @@ class Message(JsonDeserializable): _subs[type] = self.custom_subs[type] utf16_text = text.encode("utf-16-le") html_text = "" + def func(text, type=None, url=None, user=None): text = text.decode("utf-16-le") if type == "text_mention": @@ -501,6 +502,7 @@ class Message(JsonDeserializable): def html_caption(self): return self.__html_text(self.caption, self.caption_entities) + class MessageEntity(JsonDeserializable): @classmethod def de_json(cls, json_string): @@ -1069,7 +1071,7 @@ class InputVenueMessageContent(Dictionaryable): def to_dic(self): json_dic = {'latitude': self.latitude, 'longitude': self.longitude, 'title': self.title, - 'address': self.address} + 'address' : self.address} if self.foursquare_id: json_dic['foursquare_id'] = self.foursquare_id return json_dic diff --git a/tests/test_types.py b/tests/test_types.py index 42e285b..c229bdf 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -113,6 +113,7 @@ def test_json_voice(): assert voice.duration == 0 assert voice.file_size == 10481 + def test_json_update(): json_string = r'{"update_id":938203,"message":{"message_id":241,"from":{"is_bot":true,"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) @@ -120,6 +121,7 @@ def test_json_update(): 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) @@ -127,6 +129,7 @@ def test_json_chat(): assert chat.type == 'group' assert chat.title == 'Test Title' + def test_InlineQueryResultCachedPhoto(): iq = types.InlineQueryResultCachedPhoto('aaa', 'Fileid') json_str = iq.to_json() @@ -143,6 +146,7 @@ def test_InlineQueryResultCachedPhoto_with_title(): assert 'Title' in json_str assert 'caption' not in json_str + def test_InlineQueryResultCachedPhoto_with_markup(): markup = types.InlineKeyboardMarkup() markup.add(types.InlineKeyboardButton("Google", url="http://www.google.com")) @@ -154,4 +158,3 @@ def test_InlineQueryResultCachedPhoto_with_markup(): assert 'Title' in json_str assert 'caption' not in json_str assert 'reply_markup' in json_str -