From dc032b349c1b6f42132cbed446764019e08016c5 Mon Sep 17 00:00:00 2001 From: Noam Meltzer Date: Tue, 19 Jan 2016 21:49:38 +0200 Subject: [PATCH 01/20] _try_except_req(): catch httplib.HTTPException fixes #153 --- telegram/utils/request.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/telegram/utils/request.py b/telegram/utils/request.py index 63059a704..e5493f00b 100644 --- a/telegram/utils/request.py +++ b/telegram/utils/request.py @@ -25,6 +25,13 @@ import json import socket from ssl import SSLError +try: + # python2 + from httplib import HTTPException +except ImportError: + # python3 + from http.client import HTTPException + try: from urllib.request import urlopen, urlretrieve, Request from urllib.error import HTTPError @@ -82,6 +89,8 @@ def _try_except_req(func): raise TelegramError("Timed out") raise TelegramError(str(error)) + except HTTPException as error: + raise TelegramError('HTTPException: {0!r}'.format(error)) return decorator From a6650de93de063a03767adde929d3028407a3fc1 Mon Sep 17 00:00:00 2001 From: Juan Madurga Date: Wed, 20 Jan 2016 19:56:41 +0100 Subject: [PATCH 02/20] Add context parameter to dispatcher. Handlers now can updates with a context data if required --- AUTHORS.rst | 1 + telegram/__init__.py | 5 +++- telegram/dispatcher.py | 61 +++++++++++++++++++++++++---------------- telegram/updatequeue.py | 60 ++++++++++++++++++++++++++++++++++++++++ telegram/updater.py | 10 ++----- tests/test_updater.py | 19 +++++++++++++ 6 files changed, 124 insertions(+), 32 deletions(-) create mode 100644 telegram/updatequeue.py diff --git a/AUTHORS.rst b/AUTHORS.rst index cc898d1fc..b80e5e005 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -16,6 +16,7 @@ The following wonderful people contributed directly or indirectly to this projec - `JASON0916 `_ - `jh0ker `_ - `JRoot3D `_ +- `jlmadurga `_ - `macrojames `_ - `naveenvhegde `_ - `njittam `_ diff --git a/telegram/__init__.py b/telegram/__init__.py index aadb52918..a079cc8e0 100644 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -47,8 +47,10 @@ from .update import Update from .bot import Bot from .dispatcher import Dispatcher from .jobqueue import JobQueue +from .updatequeue import UpdateQueue from .updater import Updater + __author__ = 'devs@python-telegram-bot.org' __version__ = '3.2.0' __all__ = ('Bot', 'Updater', 'Dispatcher', 'Emoji', 'TelegramError', @@ -56,4 +58,5 @@ __all__ = ('Bot', 'Updater', 'Dispatcher', 'Emoji', 'TelegramError', 'ReplyKeyboardMarkup', 'UserProfilePhotos', 'ChatAction', 'Location', 'Contact', 'Video', 'Sticker', 'Document', 'File', 'Audio', 'PhotoSize', 'Chat', 'Update', 'ParseMode', 'Message', - 'User', 'TelegramObject', 'NullHandler', 'Voice', 'JobQueue') + 'User', 'TelegramObject', 'NullHandler', 'Voice', 'JobQueue', + 'UpdateQueue') diff --git a/telegram/dispatcher.py b/telegram/dispatcher.py index 9ad8966a2..16e754c5d 100644 --- a/telegram/dispatcher.py +++ b/telegram/dispatcher.py @@ -108,6 +108,11 @@ class Dispatcher: Example: '/add item1 item2 item3' -> ['item1', 'item2', 'item3'] For other updates, args will be None + Sometimes to handle update you need some context data. You can define + handlers with context parameter. To produce context just queue in + update_queue.put(update,context=context) or + processUpdate(update,context=context). + For regex-based handlers, you can also request information about the match. For all other handlers, these will be None @@ -121,7 +126,7 @@ class Dispatcher: Args: bot (telegram.Bot): The bot object that should be passed to the handlers - update_queue (queue.Queue): The synchronized queue that will + update_queue (UpdateQueue): The synchronized queue that will contain the updates. """ def __init__(self, bot, update_queue, workers=4): @@ -171,14 +176,15 @@ class Dispatcher: try: # Pop update from update queue. # Blocks if no updates are available. - update = self.update_queue.get() + update, context = self.update_queue.get(context=True) if type(update) is self._Stop: self.running = False break - self.processUpdate(update) - self.logger.debug('Processed Update: %s' % update) + self.processUpdate(update, context) + self.logger.debug('Processed Update: %s with context %s' + % (update, context)) # Dispatch any errors except TelegramError as te: @@ -204,7 +210,7 @@ class Dispatcher: while self.running: sleep(0.1) - def processUpdate(self, update): + def processUpdate(self, update, context=None): """ Processes a single update. @@ -217,15 +223,15 @@ class Dispatcher: # Custom type handlers for t in self.type_handlers: if isinstance(update, t): - self.dispatchType(update) + self.dispatchType(update, context) handled = True # string update if type(update) is str and update.startswith('/'): - self.dispatchStringCommand(update) + self.dispatchStringCommand(update, context) handled = True elif type(update) is str: - self.dispatchRegex(update) + self.dispatchRegex(update, context) handled = True # An error happened while polling @@ -235,18 +241,18 @@ class Dispatcher: # Telegram update (regex) if isinstance(update, Update): - self.dispatchRegex(update) + self.dispatchRegex(update, context) handled = True # Telegram update (command) if isinstance(update, Update) \ and update.message.text.startswith('/'): - self.dispatchTelegramCommand(update) + self.dispatchTelegramCommand(update, context) handled = True # Telegram update (message) elif isinstance(update, Update): - self.dispatchTelegramMessage(update) + self.dispatchTelegramMessage(update, context) handled = True # Update not recognized @@ -492,7 +498,7 @@ class Dispatcher: and handler in self.type_handlers[the_type]: self.type_handlers[the_type].remove(handler) - def dispatchTelegramCommand(self, update): + def dispatchTelegramCommand(self, update, context=None): """ Dispatches an update that contains a command. @@ -505,11 +511,13 @@ class Dispatcher: command = update.message.text.split(' ')[0][1:].split('@')[0] if command in self.telegram_command_handlers: - self.dispatchTo(self.telegram_command_handlers[command], update) + self.dispatchTo(self.telegram_command_handlers[command], update, + context=context) else: - self.dispatchTo(self.unknown_telegram_command_handlers, update) + self.dispatchTo(self.unknown_telegram_command_handlers, update, + context=context) - def dispatchRegex(self, update): + def dispatchRegex(self, update, context=None): """ Dispatches an update to all string or telegram regex handlers that match the string/message content. @@ -532,9 +540,10 @@ class Dispatcher: self.call_handler(handler, update, groups=m.groups(), - groupdict=m.groupdict()) + groupdict=m.groupdict(), + context=context) - def dispatchStringCommand(self, update): + def dispatchStringCommand(self, update, context=None): """ Dispatches a string-update that contains a command. @@ -545,11 +554,13 @@ class Dispatcher: command = update.split(' ')[0][1:] if command in self.string_command_handlers: - self.dispatchTo(self.string_command_handlers[command], update) + self.dispatchTo(self.string_command_handlers[command], update, + context=context) else: - self.dispatchTo(self.unknown_string_command_handlers, update) + self.dispatchTo(self.unknown_string_command_handlers, update, + context=context) - def dispatchType(self, update): + def dispatchType(self, update, context=None): """ Dispatches an update of any type. @@ -559,9 +570,9 @@ class Dispatcher: for t in self.type_handlers: if isinstance(update, t): - self.dispatchTo(self.type_handlers[t], update) + self.dispatchTo(self.type_handlers[t], update, context=context) - def dispatchTelegramMessage(self, update): + def dispatchTelegramMessage(self, update, context=None): """ Dispatches an update that contains a regular message. @@ -570,7 +581,8 @@ class Dispatcher: message. """ - self.dispatchTo(self.telegram_message_handlers, update) + self.dispatchTo(self.telegram_message_handlers, update, + context=context) def dispatchError(self, update, error): """ @@ -635,4 +647,7 @@ class Dispatcher: if is_async or 'groupdict' in fargs: target_kwargs['groupdict'] = kwargs.get('groupdict', None) + if 'context' in fargs: + target_kwargs['context'] = kwargs.get('context', None) + handler(self.bot, update, **target_kwargs) diff --git a/telegram/updatequeue.py b/telegram/updatequeue.py new file mode 100644 index 000000000..d59ee08e4 --- /dev/null +++ b/telegram/updatequeue.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2016 +# Leandro Toledo de Souza +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. + +"""This module contains the class UpdateQueue to override standard +Queue.""" + + +# Adjust for differences in Python versions +try: + from queue import Queue +except ImportError: + from Queue import Queue + + +class UpdateQueue(Queue): + """ + This class overrides standard Queues. Allows you to de/queue context + data apart from the handled `update` + """ + + def put(self, item, block=True, timeout=None, context=None): + """ + Put an item into the queue with context data if provided as a + tuple (item, context). Overrides standard Queue.put method. + + Args: + update (any): handled by the dispatcher + context (any): extra data to use in handlers + """ + Queue.put(self, (item, context), block, timeout) + + def get(self, block=True, timeout=None, context=False): + """ + Remove and return an item from the queue. A tuple of + (update, context) if required. Overrides standard Queue.get + method. + + Args: + update (any): handled by the dispatcher + context (any): extra data to use in handlers + """ + if not context: + return Queue.get(self, block, timeout)[0] + return Queue.get(self, block, timeout) diff --git a/telegram/updater.py b/telegram/updater.py index 5903b63ec..cd9d3f3f5 100644 --- a/telegram/updater.py +++ b/telegram/updater.py @@ -29,15 +29,9 @@ from time import sleep import subprocess from signal import signal, SIGINT, SIGTERM, SIGABRT from telegram import (Bot, TelegramError, dispatcher, Dispatcher, - NullHandler, JobQueue) + NullHandler, JobQueue, UpdateQueue) from telegram.utils.webhookhandler import (WebhookServer, WebhookHandler) -# Adjust for differences in Python versions -try: - from Queue import Queue -except ImportError: - from queue import Queue - try: from urllib2 import URLError except ImportError: @@ -89,7 +83,7 @@ class Updater: self.bot = bot else: self.bot = Bot(token, base_url) - self.update_queue = Queue() + self.update_queue = UpdateQueue() self.job_queue = JobQueue(self.bot, job_queue_tick_interval) self.dispatcher = Dispatcher(self.bot, self.update_queue, workers=workers) diff --git a/tests/test_updater.py b/tests/test_updater.py index 7e42da625..3c1472a43 100644 --- a/tests/test_updater.py +++ b/tests/test_updater.py @@ -109,6 +109,11 @@ class UpdaterTest(BaseTest, unittest.TestCase): update_queue.put('/test5 noresend') elif args[0] == 'noresend': pass + + def contextTest(self, bot, update, context): + self.received_message = update + self.message_count += 1 + self.context = context @run_async def asyncAdditionalHandlerTest(self, bot, update, update_queue=None, @@ -348,6 +353,20 @@ class UpdaterTest(BaseTest, unittest.TestCase): sleep(.1) self.assertEqual(self.received_message, '/test5 noresend') self.assertEqual(self.message_count, 2) + + def test_context(self): + print('Testing context for handlers') + context = "context_data" + self._setup_updater('', messages=0) + self.updater.dispatcher.addStringCommandHandler( + 'test_context', self.contextTest) + + queue = self.updater.start_polling(0.01) + queue.put('/test_context', context=context) + sleep(.5) + self.assertEqual(self.received_message, '/test_context') + self.assertEqual(self.message_count, 1) + self.assertEqual(self.context, context) def test_regexGroupHandler(self): print('Testing optional groups and groupdict parameters') From 1dc9907a709b944b4e754d72cf09f6111ef83b4f Mon Sep 17 00:00:00 2001 From: Juan Madurga Date: Fri, 22 Jan 2016 16:30:55 +0100 Subject: [PATCH 03/20] fix code comments by jh0ker --- telegram/dispatcher.py | 12 +++++++----- telegram/updatequeue.py | 6 +++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/telegram/dispatcher.py b/telegram/dispatcher.py index 16e754c5d..a4839480d 100644 --- a/telegram/dispatcher.py +++ b/telegram/dispatcher.py @@ -107,11 +107,13 @@ class Dispatcher: except the first word (usually the command). Example: '/add item1 item2 item3' -> ['item1', 'item2', 'item3'] For other updates, args will be None - - Sometimes to handle update you need some context data. You can define - handlers with context parameter. To produce context just queue in - update_queue.put(update,context=context) or + + In some cases handlers may need some context data to process the update. To + procedure just queue in update_queue.put(update, context=context) or processUpdate(update,context=context). + + context: + Extra data for handling updates. For regex-based handlers, you can also request information about the match. For all other handlers, these will be None @@ -647,7 +649,7 @@ class Dispatcher: if is_async or 'groupdict' in fargs: target_kwargs['groupdict'] = kwargs.get('groupdict', None) - if 'context' in fargs: + if is_async or 'context' in fargs: target_kwargs['context'] = kwargs.get('context', None) handler(self.bot, update, **target_kwargs) diff --git a/telegram/updatequeue.py b/telegram/updatequeue.py index d59ee08e4..7222cc1e5 100644 --- a/telegram/updatequeue.py +++ b/telegram/updatequeue.py @@ -48,12 +48,12 @@ class UpdateQueue(Queue): def get(self, block=True, timeout=None, context=False): """ Remove and return an item from the queue. A tuple of - (update, context) if required. Overrides standard Queue.get + (update, context) if requested. Overrides standard Queue.get method. Args: - update (any): handled by the dispatcher - context (any): extra data to use in handlers + context (boolean): set true to get (update, context) + """ if not context: return Queue.get(self, block, timeout)[0] From cbcbfab45f44e12d1660c9ba2808563ec23ec4b1 Mon Sep 17 00:00:00 2001 From: Juan Madurga Date: Fri, 22 Jan 2016 16:42:39 +0100 Subject: [PATCH 04/20] fix pep8 --- telegram/dispatcher.py | 6 +++--- telegram/updatequeue.py | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/telegram/dispatcher.py b/telegram/dispatcher.py index a4839480d..ac64a2867 100644 --- a/telegram/dispatcher.py +++ b/telegram/dispatcher.py @@ -107,13 +107,13 @@ class Dispatcher: except the first word (usually the command). Example: '/add item1 item2 item3' -> ['item1', 'item2', 'item3'] For other updates, args will be None - + In some cases handlers may need some context data to process the update. To procedure just queue in update_queue.put(update, context=context) or processUpdate(update,context=context). - + context: - Extra data for handling updates. + Extra data for handling updates. For regex-based handlers, you can also request information about the match. For all other handlers, these will be None diff --git a/telegram/updatequeue.py b/telegram/updatequeue.py index 7222cc1e5..21032a4da 100644 --- a/telegram/updatequeue.py +++ b/telegram/updatequeue.py @@ -53,7 +53,6 @@ class UpdateQueue(Queue): Args: context (boolean): set true to get (update, context) - """ if not context: return Queue.get(self, block, timeout)[0] From 17c28576226aeffd68527bb26c280e44302c853b Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 14:24:34 +0300 Subject: [PATCH 05/20] add module for botan analytics --- telegram/utils/botan.py | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 telegram/utils/botan.py diff --git a/telegram/utils/botan.py b/telegram/utils/botan.py new file mode 100644 index 000000000..da1d7ee53 --- /dev/null +++ b/telegram/utils/botan.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +import json + +try: + from urllib.request import urlopen, Request + from urllib.parse import quote + from urllib.error import URLError +except ImportError: + from urllib2 import urlopen, Request + from urllib import quote + from urllib2 import URLError + + +class Botan(object): + token = '' + url_template = 'https://api.botan.io/track?token={token}&uid={uid}&name={name}' + + def __init__(self, token): + self.token = token + + def track(self, message, event_name='event'): + try: + uid = message.chat_id + except AttributeError: + print('no chat_id in message') + return False + data = json.dumps(message.__dict__) + try: + url = self.url_template.format(token=str(self.token), uid=str(uid), name=quote(event_name)) + request = Request(url, + data=data, + headers={'Content-Type': 'application/json'}) + response = urlopen(request, json.dumps(data)) + if response.getcode() != 200: + return False + return True + except URLError as error: + print('botan track error ' + str(error.code) + ':' + error.reason) + print(url) + return False + From 7931045bf3fa1ef2ba171498121d8935043ed131 Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 14:24:49 +0300 Subject: [PATCH 06/20] test for botan analytics module --- tests/botan.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/botan.py diff --git a/tests/botan.py b/tests/botan.py new file mode 100644 index 000000000..304618f5f --- /dev/null +++ b/tests/botan.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +"""This module contains a object that represents Tests for Botan analytics integration""" + +import os +import unittest +import sys +sys.path.append('.') + +from telegram.utils.botan import Botan +from tests.base import BaseTest + +class MessageMock(object): + chat_id = None + + def __init__(self, chat_id): + self.chat_id = chat_id + +class BotanTest(BaseTest, unittest.TestCase): + """This object represents Tests for Botan analytics integration.""" + token = os.environ.get('TOKEN') + + def test_track(self): + """Test sending event to botan""" + print('Test sending event to botan') + botan = Botan(self.token) + message = MessageMock(self._chat_id) + result = botan.track(message, 'named event') + self.assertTrue(result) + + + def test_track_fail(self): + """Test fail when sending event to botan""" + print('Test fail when sending event to botan') + botan = Botan(self.token) + botan.url_template = 'https://api.botan.io/traccc?token={token}&uid={uid}&name={name}' + message = MessageMock(self._chat_id) + result = botan.track(message, 'named event') + self.assertFalse(result) + +if __name__ == '__main__': + unittest.main() From 545767ea40fed4f5b420c9d8f3d04f0a243a9a4b Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 14:25:09 +0300 Subject: [PATCH 07/20] add myself to authors --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index cc898d1fc..c21c55e0e 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -20,6 +20,7 @@ The following wonderful people contributed directly or indirectly to this projec - `naveenvhegde `_ - `njittam `_ - `Noam Meltzer `_ +- `Oleg Shlyazhko `_ - `Rahiel Kasim `_ - `sooyhwang `_ - `wjt `_ From adb446abf699ece2491b802cd0c0d57915ddb074 Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 15:14:17 +0300 Subject: [PATCH 08/20] fix pep8 styling --- telegram/utils/botan.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/telegram/utils/botan.py b/telegram/utils/botan.py index da1d7ee53..1f98af585 100644 --- a/telegram/utils/botan.py +++ b/telegram/utils/botan.py @@ -14,7 +14,8 @@ except ImportError: class Botan(object): token = '' - url_template = 'https://api.botan.io/track?token={token}&uid={uid}&name={name}' + url_template = 'https://api.botan.io/track?' \ + 'token={token}&uid={uid}&name={name}' def __init__(self, token): self.token = token @@ -27,7 +28,9 @@ class Botan(object): return False data = json.dumps(message.__dict__) try: - url = self.url_template.format(token=str(self.token), uid=str(uid), name=quote(event_name)) + url = self.url_template.format(token=str(self.token), + uid=str(uid), + name=quote(event_name)) request = Request(url, data=data, headers={'Content-Type': 'application/json'}) @@ -39,4 +42,3 @@ class Botan(object): print('botan track error ' + str(error.code) + ':' + error.reason) print(url) return False - From 5b05bcc8f2621947aee492bdba233eff0031755a Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 15:21:13 +0300 Subject: [PATCH 09/20] add http error exception handling --- telegram/utils/botan.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/telegram/utils/botan.py b/telegram/utils/botan.py index 1f98af585..4db59a0e7 100644 --- a/telegram/utils/botan.py +++ b/telegram/utils/botan.py @@ -5,11 +5,11 @@ import json try: from urllib.request import urlopen, Request from urllib.parse import quote - from urllib.error import URLError + from urllib.error import URLError, HTTPError except ImportError: from urllib2 import urlopen, Request from urllib import quote - from urllib2 import URLError + from urllib2 import URLError, HTTPError class Botan(object): @@ -38,7 +38,9 @@ class Botan(object): if response.getcode() != 200: return False return True - except URLError as error: + except HTTPError as error: print('botan track error ' + str(error.code) + ':' + error.reason) - print(url) + return False + except URLError as error: + print('botan track error ' + error.reason) return False From 2c12bd6775be0a6f3d2be36dd29b895d300ce479 Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 16:58:01 +0300 Subject: [PATCH 10/20] replace print with logging --- telegram/utils/botan.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/telegram/utils/botan.py b/telegram/utils/botan.py index 4db59a0e7..67d33fe65 100644 --- a/telegram/utils/botan.py +++ b/telegram/utils/botan.py @@ -1,6 +1,8 @@ #!/usr/bin/env python import json +import logging +from telegram import NullHandler try: from urllib.request import urlopen, Request @@ -11,6 +13,9 @@ except ImportError: from urllib import quote from urllib2 import URLError, HTTPError +H = NullHandler() +logging.getLogger(__name__).addHandler(H) + class Botan(object): token = '' @@ -19,12 +24,13 @@ class Botan(object): def __init__(self, token): self.token = token + self.logger = logging.getLogger(__name__) def track(self, message, event_name='event'): try: uid = message.chat_id except AttributeError: - print('no chat_id in message') + self.logger.warn('No chat_id in message') return False data = json.dumps(message.__dict__) try: @@ -39,8 +45,9 @@ class Botan(object): return False return True except HTTPError as error: - print('botan track error ' + str(error.code) + ':' + error.reason) + self.logger.warn('Botan track error ' + + str(error.code) + ':' + error.reason) return False except URLError as error: - print('botan track error ' + error.reason) + self.logger.warn('Botan track error ' + error.reason) return False From bb2cce56a387a0d665ae37569788f0188d7794ab Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 16:58:44 +0300 Subject: [PATCH 11/20] insert correct appmetrica token instead of bot token in botan test --- tests/botan.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/botan.py b/tests/botan.py index 304618f5f..b33521b0e 100644 --- a/tests/botan.py +++ b/tests/botan.py @@ -18,7 +18,8 @@ class MessageMock(object): class BotanTest(BaseTest, unittest.TestCase): """This object represents Tests for Botan analytics integration.""" - token = os.environ.get('TOKEN') + + token = '26c6df87-56ea-4764-a588-0e25de3a64a9' def test_track(self): """Test sending event to botan""" From 7508c2f8bf6e6b585799a96500819d75b2a3aa77 Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 16:59:53 +0300 Subject: [PATCH 12/20] add detailed comment in class and src key to tracking url --- telegram/utils/botan.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/telegram/utils/botan.py b/telegram/utils/botan.py index 67d33fe65..9d8716146 100644 --- a/telegram/utils/botan.py +++ b/telegram/utils/botan.py @@ -18,9 +18,12 @@ logging.getLogger(__name__).addHandler(H) class Botan(object): + """This class helps to send incoming events in your botan analytics account. + See more: https://github.com/botanio/sdk#botan-sdk""" + token = '' - url_template = 'https://api.botan.io/track?' \ - 'token={token}&uid={uid}&name={name}' + url_template = 'https://api.botan.io/track?token={token}' \ + '&uid={uid}&name={name}&src=python-telegram-bot' def __init__(self, token): self.token = token From 5a2a541ae0426402d757a3647c3ef4d78dcab6ad Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 19:09:56 +0300 Subject: [PATCH 13/20] rename botan test correctly and move token to ENV --- tests/{botan.py => test_botan.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/{botan.py => test_botan.py} (95%) diff --git a/tests/botan.py b/tests/test_botan.py similarity index 95% rename from tests/botan.py rename to tests/test_botan.py index b33521b0e..f99eb1b84 100644 --- a/tests/botan.py +++ b/tests/test_botan.py @@ -19,7 +19,7 @@ class MessageMock(object): class BotanTest(BaseTest, unittest.TestCase): """This object represents Tests for Botan analytics integration.""" - token = '26c6df87-56ea-4764-a588-0e25de3a64a9' + token = os.environ.get('BOTAN_TOKEN') def test_track(self): """Test sending event to botan""" From 0faa38b8afb905fedc9bb7f11b39e1e6d8081760 Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 19:29:01 +0300 Subject: [PATCH 14/20] fix httperror logging --- telegram/utils/botan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram/utils/botan.py b/telegram/utils/botan.py index 9d8716146..1dd8c4478 100644 --- a/telegram/utils/botan.py +++ b/telegram/utils/botan.py @@ -49,7 +49,7 @@ class Botan(object): return True except HTTPError as error: self.logger.warn('Botan track error ' + - str(error.code) + ':' + error.reason) + str(error.code) + ':' + error.read()) return False except URLError as error: self.logger.warn('Botan track error ' + error.reason) From 80b53f1ab702a1662c0f5489509dafccd622ec58 Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 19:44:40 +0300 Subject: [PATCH 15/20] fix urlopen call --- telegram/utils/botan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram/utils/botan.py b/telegram/utils/botan.py index 1dd8c4478..5b29c9ff2 100644 --- a/telegram/utils/botan.py +++ b/telegram/utils/botan.py @@ -43,7 +43,7 @@ class Botan(object): request = Request(url, data=data, headers={'Content-Type': 'application/json'}) - response = urlopen(request, json.dumps(data)) + response = urlopen(request) if response.getcode() != 200: return False return True From d1e4eeaf306276c7eb2cf481531878fa2a5b90a8 Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 19:49:55 +0300 Subject: [PATCH 16/20] fix urlopen data format --- telegram/utils/botan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram/utils/botan.py b/telegram/utils/botan.py index 5b29c9ff2..0f9cbeedc 100644 --- a/telegram/utils/botan.py +++ b/telegram/utils/botan.py @@ -41,7 +41,7 @@ class Botan(object): uid=str(uid), name=quote(event_name)) request = Request(url, - data=data, + data=data.encode(), headers={'Content-Type': 'application/json'}) response = urlopen(request) if response.getcode() != 200: From 383a2d3742480f7f2bf1026e9384ddf56d812589 Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 20:03:29 +0300 Subject: [PATCH 17/20] fix httperror error output --- telegram/utils/botan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram/utils/botan.py b/telegram/utils/botan.py index 0f9cbeedc..075e146bc 100644 --- a/telegram/utils/botan.py +++ b/telegram/utils/botan.py @@ -49,7 +49,7 @@ class Botan(object): return True except HTTPError as error: self.logger.warn('Botan track error ' + - str(error.code) + ':' + error.read()) + str(error.code) + ':' + error.read().decode('utf-8')) return False except URLError as error: self.logger.warn('Botan track error ' + error.reason) From 9eec34edd1719836fa6359f4248aec111a413ffb Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sat, 23 Jan 2016 20:13:48 +0300 Subject: [PATCH 18/20] pep8 fix --- telegram/utils/botan.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telegram/utils/botan.py b/telegram/utils/botan.py index 075e146bc..37c8c928f 100644 --- a/telegram/utils/botan.py +++ b/telegram/utils/botan.py @@ -49,7 +49,8 @@ class Botan(object): return True except HTTPError as error: self.logger.warn('Botan track error ' + - str(error.code) + ':' + error.read().decode('utf-8')) + str(error.code) + + ':' + error.read().decode('utf-8')) return False except URLError as error: self.logger.warn('Botan track error ' + error.reason) From c3bca9af486c2c341d2b57ac1d3288d1310bff5d Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sun, 24 Jan 2016 18:28:27 +0300 Subject: [PATCH 19/20] remove checking for non 200 http codes, exceptions already handle it --- telegram/utils/botan.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/telegram/utils/botan.py b/telegram/utils/botan.py index 37c8c928f..1c6b774c3 100644 --- a/telegram/utils/botan.py +++ b/telegram/utils/botan.py @@ -43,9 +43,7 @@ class Botan(object): request = Request(url, data=data.encode(), headers={'Content-Type': 'application/json'}) - response = urlopen(request) - if response.getcode() != 200: - return False + urlopen(request) return True except HTTPError as error: self.logger.warn('Botan track error ' + @@ -53,5 +51,5 @@ class Botan(object): ':' + error.read().decode('utf-8')) return False except URLError as error: - self.logger.warn('Botan track error ' + error.reason) + self.logger.warn('Botan track error ' + str(error.reason)) return False From 1000a56e0de74d91de1c5861d5d728e884e9966a Mon Sep 17 00:00:00 2001 From: Oleg Shlyazhko Date: Sun, 24 Jan 2016 18:32:12 +0300 Subject: [PATCH 20/20] more test vor botan module, increase coverage --- tests/test_botan.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/test_botan.py b/tests/test_botan.py index f99eb1b84..1206b8bab 100644 --- a/tests/test_botan.py +++ b/tests/test_botan.py @@ -10,12 +10,14 @@ sys.path.append('.') from telegram.utils.botan import Botan from tests.base import BaseTest + class MessageMock(object): chat_id = None def __init__(self, chat_id): self.chat_id = chat_id + class BotanTest(BaseTest, unittest.TestCase): """This object represents Tests for Botan analytics integration.""" @@ -29,7 +31,6 @@ class BotanTest(BaseTest, unittest.TestCase): result = botan.track(message, 'named event') self.assertTrue(result) - def test_track_fail(self): """Test fail when sending event to botan""" print('Test fail when sending event to botan') @@ -39,5 +40,23 @@ class BotanTest(BaseTest, unittest.TestCase): result = botan.track(message, 'named event') self.assertFalse(result) + def test_wrong_message(self): + """Test sending wrong message""" + print('Test sending wrong message') + botan = Botan(self.token) + message = MessageMock(self._chat_id) + message = delattr(message, 'chat_id') + result = botan.track(message, 'named event') + self.assertFalse(result) + + def test_wrong_endpoint(self): + """Test wrong endpoint""" + print('Test wrong endpoint') + botan = Botan(self.token) + botan.url_template = 'https://api.botaaaaan.io/traccc?token={token}&uid={uid}&name={name}' + message = MessageMock(self._chat_id) + result = botan.track(message, 'named event') + self.assertFalse(result) + if __name__ == '__main__': unittest.main()