From c81bdfec99e580d62bc6fdff9127fa167e927ccc Mon Sep 17 00:00:00 2001 From: Jeff Ammons Date: Sun, 5 Jun 2016 13:28:28 -0700 Subject: [PATCH] Fix unicode error in py2.7 for example plugin Strings should now be passed to the plugins as unicode values in py2.7 so we have to make sure that we don't convert those into ascii by using python str instead of u'' strings. --- README.md | 2 ++ doc/example-plugins/canary.py | 3 +++ doc/example-plugins/counter.py | 3 +++ doc/example-plugins/repeat.py | 3 +++ doc/example-plugins/todo.py | 3 +++ rtmbot/core.py | 4 ++-- setup.py | 2 +- tests/test_rtmbot_core.py | 32 ++++++++++++++++++++++++-------- 8 files changed, 41 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 19e1aa3..062c3d2 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,8 @@ This will print the incoming message json (dict) to the screen where the bot is Plugins having a method defined as ```catch_all(data)``` will receive ALL events from the websocket. This is useful for learning the names of events and debugging. +Note: If you're using Python 2.x, the incoming data should be a unicode string, be careful you don't coerce it into a normal str object as it will cause errors on output. You can add `from __future__ import unicode_literals` to your plugin file to avoid this. + ####Outgoing data Plugins can send messages back to any channel, including direct messages. This is done by appending a two item array to the outputs global array. The first item in the array is the channel ID and the second is the message text. Example that writes "hello world" when the plugin is started: diff --git a/doc/example-plugins/canary.py b/doc/example-plugins/canary.py index b2cea10..5a03a00 100644 --- a/doc/example-plugins/canary.py +++ b/doc/example-plugins/canary.py @@ -1,3 +1,6 @@ +from __future__ import unicode_literals +# don't convert to ascii in py2.7 when creating string to return + import time outputs = [] diff --git a/doc/example-plugins/counter.py b/doc/example-plugins/counter.py index 00fac1a..1b03305 100644 --- a/doc/example-plugins/counter.py +++ b/doc/example-plugins/counter.py @@ -1,3 +1,6 @@ +from __future__ import unicode_literals +# don't convert to ascii in py2.7 when creating string to return + import time crontable = [] outputs = [] diff --git a/doc/example-plugins/repeat.py b/doc/example-plugins/repeat.py index 3106457..a288eb3 100644 --- a/doc/example-plugins/repeat.py +++ b/doc/example-plugins/repeat.py @@ -1,3 +1,6 @@ +from __future__ import unicode_literals +# don't convert to ascii in py2.7 when creating string to return + crontable = [] outputs = [] diff --git a/doc/example-plugins/todo.py b/doc/example-plugins/todo.py index cd1db8d..3fba6cd 100644 --- a/doc/example-plugins/todo.py +++ b/doc/example-plugins/todo.py @@ -1,4 +1,7 @@ from __future__ import print_function +from __future__ import unicode_literals +# don't convert to ascii in py2.7 when creating string to return + import os import pickle diff --git a/rtmbot/core.py b/rtmbot/core.py index 9cc507d..1b391a3 100755 --- a/rtmbot/core.py +++ b/rtmbot/core.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import unicode_literals import sys import glob import os @@ -101,8 +102,7 @@ class RtmBot(object): if limiter: time.sleep(.1) limiter = False - message = output[1] - channel.send_message("{}".format(message)) + channel.send_message(output[1]) limiter = True def crons(self): diff --git a/setup.py b/setup.py index ef6cfc3..3f670ef 100755 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from distutils.core import setup setup( name='rtmbot', - version='0.10', + version='0.2.0', description='A Slack bot written in python that connects via the RTM API.', author='Ryan Huber', author_email='rhuber@gmail.com', diff --git a/tests/test_rtmbot_core.py b/tests/test_rtmbot_core.py index 85d7563..ef0a8ca 100644 --- a/tests/test_rtmbot_core.py +++ b/tests/test_rtmbot_core.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- try: - from unittest.mock import Mock + from unittest.mock import Mock, create_autospec except ImportError: - from mock import Mock + from mock import Mock, create_autospec from testfixtures import LogCapture -from rtmbot.core import RtmBot +from slackclient import SlackClient, _channel, _server, _util +from rtmbot.core import RtmBot, Plugin def init_rtmbot(): ''' Initializes an instance of RTMBot with some default values ''' @@ -33,14 +34,21 @@ def test_output(): ''' Test that sending a message behaves as expected ''' rtmbot = init_rtmbot() - # Mock the slack_client object - slackclient_mock = Mock() - channel_mock = Mock() + # Mock the slack_client object with Server, Channel objects and needed methods + slackclient_mock = create_autospec(SlackClient) + server_mock = create_autospec(_server.Server) + + # Mock Server with channels method and correct return value + slackclient_mock.server = server_mock + searchlist_mock = create_autospec(_util.SearchList) + server_mock.channels = searchlist_mock + channel_mock = create_autospec(_channel.Channel) slackclient_mock.server.channels.find.return_value = channel_mock + rtmbot.slack_client = slackclient_mock # mock the plugin object to return a sample response - plugin_mock = Mock() + plugin_mock = create_autospec(Plugin) plugin_mock.do_output.return_value = [['C12345678', 'test message']] rtmbot.bot_plugins.append(plugin_mock) @@ -50,10 +58,18 @@ def test_output(): # test that the output matches the expected value channel_mock.send_message.assert_called_with('test message') - # test that unicode messages work as expected + # test that emoji messages work as expected channel_mock.reset_mock() plugin_mock.reset_mock() plugin_mock.do_output.return_value = [['C12345678', '🚀 testing']] rtmbot.output() channel_mock.send_message.assert_called_with('🚀 testing') + + # test that unicode messages work as expected + channel_mock.reset_mock() + plugin_mock.reset_mock() + plugin_mock.do_output.return_value = [['C12345678', 'ù hœø3ö']] + rtmbot.output() + + channel_mock.send_message.assert_called_with('ù hœø3ö') \ No newline at end of file