Repository: watson-developer-cloud/python-sdk

Issue:
Python SDK requires Conversation API implementation for 'workspaces' endpoint.
The new Conversation endpoint supports the management of workspaces via the /workspaces API endpoint.  This functionality needs to be implemented ASAP

https://watson-api-explorer.mybluemix.net/apis/conversation-v1



Discussion:

Patch:
diff --git a/examples/notebooks/conversation_v1.ipynb b/examples/notebooks/conversation_v1.ipynb
new file mode 100644
index 00000000..73515bc7
--- /dev/null
+++ b/examples/notebooks/conversation_v1.ipynb
@@ -0,0 +1,366 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {
+    "collapsed": false,
+    "deletable": true,
+    "editable": true
+   },
+   "outputs": [],
+   "source": [
+    "import json\n",
+    "import sys\n",
+    "import os\n",
+    "sys.path.append(os.path.join(os.getcwd(),'..','..'))\n",
+    "import watson_developer_cloud"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {
+    "collapsed": true,
+    "deletable": true,
+    "editable": true
+   },
+   "outputs": [],
+   "source": [
+    "USERNAME = os.environ.get('CONVERSATION_USERNAME','<USERNAME>')\n",
+    "PASSWORD = os.environ.get('CONVERSATION_PASSWORD','<PASSWORD>')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {
+    "collapsed": false,
+    "deletable": true,
+    "editable": true
+   },
+   "outputs": [],
+   "source": [
+    "conversation = watson_developer_cloud.ConversationV1(username=USERNAME,\n",
+    "                                                     password=PASSWORD,\n",
+    "                                                     version='2016-09-20')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
+   "metadata": {
+    "collapsed": false,
+    "deletable": true,
+    "editable": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'pagination': {'refresh_url': '/v1/workspaces?version=2016-09-20'},\n",
+       " 'workspaces': [{'created': '2017-02-09T19:46:26.792Z',\n",
+       "   'description': 'yo dawg',\n",
+       "   'language': 'en',\n",
+       "   'metadata': None,\n",
+       "   'name': 'development',\n",
+       "   'updated': '2017-02-09T20:00:38.558Z',\n",
+       "   'workspace_id': '8c8ee3b3-6149-4bc0-ba66-6517fd6c976a'}]}"
+      ]
+     },
+     "execution_count": 28,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "conversation.list_workspaces()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "metadata": {
+    "collapsed": false,
+    "deletable": true,
+    "editable": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{'name': 'my experimental workspace', 'created': '2017-02-09T21:48:35.245Z', 'updated': '2017-02-09T21:48:35.245Z', 'language': 'en', 'metadata': None, 'description': 'an experimental workspace', 'workspace_id': 'dbd1211f-3abb-4165-8a67-8bfa95410aa9'}\n"
+     ]
+    }
+   ],
+   "source": [
+    "new_workspace = conversation.create_workspace(name='my experimental workspace',\n",
+    "                                              description='an experimental workspace',\n",
+    "                                              language='en',\n",
+    "                                              intents=[{\n",
+    "                                                      \"intent\": \"orderpizza\",\n",
+    "                                                      \"examples\": [\n",
+    "                                                            {\n",
+    "                                                              \"text\": \"can I order a pizza?\"\n",
+    "                                                            },\n",
+    "                                                            {\n",
+    "                                                              \"text\": \"I want to order a pizza\"\n",
+    "                                                            },\n",
+    "                                                            {\n",
+    "                                                              \"text\": \"pizza order\"\n",
+    "                                                            },\n",
+    "                                                            {\n",
+    "                                                              \"text\": \"pizza to go\"\n",
+    "                                                            }\n",
+    "                                                          ],\n",
+    "                                                          \"description\": \"pizza intents\"\n",
+    "                                                        }\n",
+    "                                               ],\n",
+    "                                              dialog_nodes=[{'conditions': '#orderpizza',\n",
+    "                                                             'context': None,\n",
+    "                                                             'description': None,\n",
+    "                                                             'dialog_node': 'YesYouCan',\n",
+    "                                                             'go_to': None,\n",
+    "                                                             'metadata': None,\n",
+    "                                                             'output':  {'text': {'selection_policy': 'random',\n",
+    "                                                                                   'values': \n",
+    "                                                                                   ['Yes You can!', 'Of course!']}},\n",
+    "                                                             'parent': None,\n",
+    "                                                             'previous_sibling': None,}])\n",
+    "print(new_workspace)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {
+    "collapsed": false,
+    "deletable": true,
+    "editable": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'created': '2017-02-09T21:48:35.245Z',\n",
+       " 'description': 'an experimental workspace',\n",
+       " 'language': 'en',\n",
+       " 'metadata': None,\n",
+       " 'name': 'my experimental workspace',\n",
+       " 'status': 'Training',\n",
+       " 'updated': '2017-02-09T21:48:35.245Z',\n",
+       " 'workspace_id': 'dbd1211f-3abb-4165-8a67-8bfa95410aa9'}"
+      ]
+     },
+     "execution_count": 31,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "conversation.get_workspace(workspace_id=new_workspace['workspace_id'])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {
+    "collapsed": false,
+    "deletable": true,
+    "editable": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'created': '2017-02-09T21:39:30.390Z',\n",
+       " 'description': 'an experimental workspace',\n",
+       " 'language': 'en',\n",
+       " 'metadata': None,\n",
+       " 'name': 'changed name',\n",
+       " 'updated': '2017-02-09T21:39:59.124Z',\n",
+       " 'workspace_id': '66e78807-13fa-47ae-9251-dd8c89c8fd19'}"
+      ]
+     },
+     "execution_count": 20,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "new_workspace['name'] = 'changed name'\n",
+    "conversation.update_workspace(new_workspace['workspace_id'], name=new_workspace['name'])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {
+    "collapsed": false,
+    "deletable": true,
+    "editable": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'counterexamples': [],\n",
+       " 'created': '2017-02-09T21:48:35.245Z',\n",
+       " 'description': 'an experimental workspace',\n",
+       " 'dialog_nodes': [{'conditions': '#orderpizza',\n",
+       "   'context': None,\n",
+       "   'created': '2017-02-09T21:48:35.245Z',\n",
+       "   'description': None,\n",
+       "   'dialog_node': 'YesYouCan',\n",
+       "   'go_to': None,\n",
+       "   'metadata': None,\n",
+       "   'output': {'text': {'selection_policy': 'random',\n",
+       "     'values': ['Yes You can!', 'Of course!']}},\n",
+       "   'parent': None,\n",
+       "   'previous_sibling': None,\n",
+       "   'updated': '2017-02-09T21:48:35.245Z'}],\n",
+       " 'entities': [],\n",
+       " 'intents': [{'created': '2017-02-09T21:48:35.245Z',\n",
+       "   'description': 'pizza intents',\n",
+       "   'examples': [{'created': '2017-02-09T21:48:35.245Z',\n",
+       "     'text': 'can I order a pizza?',\n",
+       "     'updated': '2017-02-09T21:48:35.245Z'},\n",
+       "    {'created': '2017-02-09T21:48:35.245Z',\n",
+       "     'text': 'I want to order a pizza',\n",
+       "     'updated': '2017-02-09T21:48:35.245Z'},\n",
+       "    {'created': '2017-02-09T21:48:35.245Z',\n",
+       "     'text': 'pizza order',\n",
+       "     'updated': '2017-02-09T21:48:35.245Z'},\n",
+       "    {'created': '2017-02-09T21:48:35.245Z',\n",
+       "     'text': 'pizza to go',\n",
+       "     'updated': '2017-02-09T21:48:35.245Z'}],\n",
+       "   'intent': 'orderpizza',\n",
+       "   'updated': '2017-02-09T21:48:35.245Z'}],\n",
+       " 'language': 'en',\n",
+       " 'metadata': None,\n",
+       " 'name': 'my experimental workspace',\n",
+       " 'status': 'Available',\n",
+       " 'updated': '2017-02-09T21:48:35.245Z',\n",
+       " 'workspace_id': 'dbd1211f-3abb-4165-8a67-8bfa95410aa9'}"
+      ]
+     },
+     "execution_count": 32,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "conversation.get_workspace(new_workspace['workspace_id'], export=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {
+    "collapsed": false,
+    "deletable": true,
+    "editable": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "  \"intents\": [\n",
+      "    {\n",
+      "      \"intent\": \"orderpizza\",\n",
+      "      \"confidence\": 1\n",
+      "    }\n",
+      "  ],\n",
+      "  \"entities\": [],\n",
+      "  \"input\": {\n",
+      "    \"text\": \"can I order a pizza?\"\n",
+      "  },\n",
+      "  \"output\": {\n",
+      "    \"log_messages\": [],\n",
+      "    \"text\": [\n",
+      "      \"Of course!\"\n",
+      "    ],\n",
+      "    \"nodes_visited\": [\n",
+      "      \"YesYouCan\"\n",
+      "    ]\n",
+      "  },\n",
+      "  \"context\": {\n",
+      "    \"conversation_id\": \"972f212d-be0f-47fd-a82d-a6f917e16cfd\",\n",
+      "    \"system\": {\n",
+      "      \"dialog_stack\": [\n",
+      "        {\n",
+      "          \"dialog_node\": \"root\"\n",
+      "        }\n",
+      "      ],\n",
+      "      \"dialog_turn_counter\": 1,\n",
+      "      \"dialog_request_counter\": 1,\n",
+      "      \"_node_output_map\": {\n",
+      "        \"YesYouCan\": [\n",
+      "          0,\n",
+      "          1,\n",
+      "          0\n",
+      "        ]\n",
+      "      }\n",
+      "    }\n",
+      "  },\n",
+      "  \"alternate_intents\": false\n",
+      "}\n"
+     ]
+    }
+   ],
+   "source": [
+    "response = conversation.message(workspace_id=new_workspace['workspace_id'],\n",
+    "                                message_input={'text': 'can I order a pizza?'})\n",
+    "print(json.dumps(response, indent=2))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 35,
+   "metadata": {
+    "collapsed": false,
+    "deletable": true,
+    "editable": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{}"
+      ]
+     },
+     "execution_count": 35,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "conversation.delete_workspace(new_workspace['workspace_id'])"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.6.0"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/watson_developer_cloud/conversation_v1.py b/watson_developer_cloud/conversation_v1.py
index 51fa0564..408c225b 100644
--- a/watson_developer_cloud/conversation_v1.py
+++ b/watson_developer_cloud/conversation_v1.py
@@ -30,6 +30,130 @@ class ConversationV1(WatsonDeveloperCloudService):
                                              **kwargs)
         self.version = version
 
+    def list_workspaces(self):
+        """
+        List workspaces available.
+        This includes pagination info.
+        """
+        params = {'version': self.version}
+        return self.request(method='GET',
+                            url='/v1/workspaces',
+                            params=params,
+                            accept_json=True)
+
+    def get_workspace(self, workspace_id, export=False):
+        """
+        Get a specific workspace
+        :param: workspace_id  the guid of the workspace
+        :param: export (optional) return all workspace data
+        """
+        params = {'version': self.version}
+        if export:
+            params['export'] = True
+
+        return self.request(method='GET',
+                            url='/v1/workspaces/{0}'.format(workspace_id),
+                            params=params,
+                            accept_json=True)
+
+    def delete_workspace(self, workspace_id):
+        """
+        Deletes a given workspace.
+        :param: workspace_id the guid of the workspace_id
+        """
+        params = {'version': self.version}
+        return self.request(method='DELETE',
+                            url='/v1/workspaces/{0}'.format(workspace_id),
+                            params=params,
+                            accept_json=True)
+
+    def create_workspace(self, name, description, language,
+                         intents=None,
+                         entities=None,
+                         dialog_nodes=None,
+                         counterexamples=None,
+                         metadata=None):
+        """
+        Create a new workspace
+        :param name: Name of the workspace
+        :param description: description of the worksspace
+        :param language: language code
+        :param entities: an array of entities (optional)
+        :param dialog_nodes: an array of dialog notes (optional)
+        :param counterexamples: an array of counterexamples (optional)
+        :param metadata: metadata dictionary (optional)
+        """
+        payload = {'name': name,
+                   'description': description,
+                   'language': language}
+        if intents is not None:
+            payload['intents'] = intents
+
+        if entities is not None:
+            payload['entities'] = entities
+
+        if dialog_nodes is not None:
+            payload['dialog_nodes'] = dialog_nodes
+
+        if counterexamples is not None:
+            payload['counterexamples'] = counterexamples
+
+        if metadata is not None:
+            payload['metadata'] = metadata
+
+        params = {'version': self.version}
+        return self.request(method='POST',
+                            url='/v1/workspaces',
+                            json=payload,
+                            params=params,
+                            accept_json=True)
+
+    def update_workspace(self, workspace_id,
+                         name=None,
+                         description=None,
+                         language=None,
+                         intents=None,
+                         entities=None,
+                         dialog_nodes=None,
+                         counterexamples=None,
+                         metadata=None):
+        """
+        Update an existing workspace
+        :param workspace_id: the guid of the workspace to update
+        :param name: Name of the workspace
+        :param description: description of the worksspace
+        :param language: language code
+        :param entities: an array of entities (optional)
+        :param dialog_nodes: an array of dialog notes (optional)
+        :param counterexamples: an array of counterexamples (optional)
+        :param metadata: metadata dictionary (optional)
+        """
+        params = {'version': self.version}
+        payload = {'name': name,
+                   'description': description,
+                   'language': language}
+        if intents is not None:
+            payload['intents'] = intents
+
+        if entities is not None:
+            payload['entities'] = entities
+
+        if dialog_nodes is not None:
+            payload['dialog_nodes'] = dialog_nodes
+
+        if counterexamples is not None:
+            payload['counterexamples'] = counterexamples
+
+        if metadata is not None:
+            payload['metadata'] = metadata
+
+        params = {'version': self.version}
+        return self.request(method='POST',
+                            url='/v1/workspaces/{0}'.format(workspace_id),
+                            json=payload,
+                            params=params,
+                            accept_json=True)
+
     def message(self, workspace_id, message_input=None, context=None,
                 entities=None, intents=None, output=None,
                 alternate_intents=False):


Test patch:
diff --git a/test/test_conversation_v1.py b/test/test_conversation_v1.py
index 527044c4..fb8d494a 100644
--- a/test/test_conversation_v1.py
+++ b/test/test_conversation_v1.py
@@ -1,39 +1,235 @@
+import json
 import responses
 import watson_developer_cloud
 
+platform_url = "https://gateway.watsonplatform.net"
+conversation_path = "/conversation/api/v1"
+base_url = "{0}{1}".format(platform_url, conversation_path)
+
+
+@responses.activate
+def test_list_worksapces():
+    workspace_url = "{0}{1}".format(base_url, "/workspaces")
+    message_response = {"workspaces": [],
+                        "pagination": {
+                            "refresh_url":
+                                "/v1/workspaces?version=2016-09-20"}}
+    responses.add(responses.GET, workspace_url,
+                  body=json.dumps(message_response), status=200,
+                  content_type='application/json')
+    conversation = watson_developer_cloud.ConversationV1(username="username",
+                                                         password="password",
+                                                         version='2016-09-20')
+    workspaces = conversation.list_workspaces()
+    assert 'workspaces' in workspaces
+    assert len(workspaces['workspaces']) == 0
+
+
+@responses.activate
+def test_get_workspace():
+    workspace_url = "{0}{1}/boguswid".format(base_url, "/workspaces")
+    message_response = {
+                        "name": "development",
+                        "created": "2017-02-09T18:41:19.890Z",
+                        "updated": "2017-02-09T18:41:19.890Z",
+                        "language": "en",
+                        "metadata": None,
+                        "description": "this is a workspace",
+                        "workspace_id": "boguswid",
+                        "status": 'Training',
+                        }
+    responses.add(responses.GET, workspace_url,
+                  body=json.dumps(message_response), status=200,
+                  content_type='application/json')
+    conversation = watson_developer_cloud.ConversationV1(username="username",
+                                                         password="password",
+                                                         version='2016-09-20')
+    workspace = conversation.get_workspace(workspace_id='boguswid')
+    assert workspace['name'] == 'development'
+    assert workspace['workspace_id'] == 'boguswid'
+    assert workspace['status'] == 'Training'
+
+    workspace = conversation.get_workspace(workspace_id='boguswid',
+                                           export=True)
+    assert workspace['status'] == 'Training'
+
+
+@responses.activate
+def test_delete_workspace():
+    workspace_url = "{0}{1}/boguswid".format(base_url, "/workspaces")
+    message_response = {}
+    responses.add(responses.DELETE, workspace_url,
+                  body=json.dumps(message_response), status=200,
+                  content_type='application/json')
+    conversation = watson_developer_cloud.ConversationV1(username="username",
+                                                         password="password",
+                                                         version='2016-09-20')
+    workspace = conversation.delete_workspace(workspace_id='boguswid')
+    assert len(responses.calls) == 1
+    assert workspace == {}
+
+
+@responses.activate
+def test_create_workspace():
+    workspace_data = {
+                      "name": "development",
+                      "intents": [
+                                  {
+                                   "intent": "orderpizza",
+                                   "examples": [
+                                                {
+                                                 "text": "can I order a pizza?"
+                                                }, {
+                                                 "text": "want order a pizza"
+                                                }, {
+                                                 "text": "pizza order"
+                                                }, {
+                                                 "text": "pizza to go"
+                                                }],
+                                   "description": None
+                                  }],
+                      "entities": [{'entity': 'just for testing'}],
+                      "language": "en",
+                      "metadata": {'thing': 'something'},
+                      "description": "this is a development workspace",
+                      "dialog_nodes": [{'conditions': '#orderpizza',
+                                        'context': None,
+                                        'description': None,
+                                        'dialog_node': 'YesYouCan',
+                                        'go_to': None,
+                                        'metadata': None,
+                                        'output':  {'text': {'selection_policy': 'random',
+                                                             'values': ['Yes You can!', 'Of course!']}},
+                                                             'parent': None,
+                                                             'previous_sibling': None}],
+                      "counterexamples": [{'counter': 'counterexamples for test'}]
+                      }
+
+    workspace_url = "{0}{1}".format(base_url, "/workspaces")
+    message_response = workspace_data
+    message_response["workspace_id"] = 'bogusid'
+    responses.add(responses.POST, workspace_url,
+                  body=json.dumps(message_response), status=200,
+                  content_type='application/json')
+    conversation = watson_developer_cloud.ConversationV1(username="username",
+                                                         password="password",
+                                                         version='2016-09-20')
+    workspace = conversation.create_workspace(name=workspace_data['name'],
+                                              description=workspace_data['description'],
+                                              language=workspace_data['language'],
+                                              intents=workspace_data['intents'],
+                                              metadata=workspace_data['metadata'],
+                                              counterexamples=workspace_data['counterexamples'],
+                                              dialog_nodes=workspace_data['dialog_nodes'],
+                                              entities=workspace_data['entities'])
+    assert workspace == message_response
+    assert len(responses.calls) == 1
+
+
+@responses.activate
+def test_update_workspace():
+    workspace_data = {
+                      "name": "development",
+                      "intents": [
+                                  {
+                                   "intent": "orderpizza",
+                                   "examples": [
+                                                {
+                                                 "text": "can I order a pizza?"
+                                                }, {
+                                                 "text": "want order a pizza"
+                                                }, {
+                                                 "text": "pizza order"
+                                                }, {
+                                                 "text": "pizza to go"
+                                                }],
+                                   "description": None
+                                  }],
+                      "entities": [],
+                      "language": "en",
+                      "metadata": {},
+                      "description": "this is a development workspace",
+                      "dialog_nodes": [],
+                      "counterexamples": [],
+                      "workspace_id": 'boguswid'
+                      }
+
+    workspace_url = "{0}{1}".format(base_url, "/workspaces/boguswid")
+    message_response = workspace_data
+    responses.add(responses.POST, workspace_url,
+                  body=json.dumps(message_response), status=200,
+                  content_type='application/json')
+    conversation = watson_developer_cloud.ConversationV1(username="username",
+                                                         password="password",
+                                                         version='2016-09-20')
+    workspace = conversation.update_workspace('boguswid',
+                                              name=workspace_data['name'],
+                                              description=workspace_data['description'],
+                                              language=workspace_data['language'],
+                                              intents=workspace_data['intents'],
+                                              metadata=workspace_data['metadata'],
+                                              counterexamples=workspace_data['counterexamples'],
+                                              dialog_nodes=workspace_data['dialog_nodes'],
+                                              entities=workspace_data['entities'])
+    assert len(responses.calls) == 1
+    assert workspace == message_response
+
+
 @responses.activate
 def test_message():
 
-# Ranker endpoints
     conversation = watson_developer_cloud.ConversationV1(username="username",
                                                          password="password",
                                                          version='2016-09-20')
 
     workspace_id = 'f8fdbc65-e0bd-4e43-b9f8-2975a366d4ec'
-    message_url = 'https://gateway.watsonplatform.net/conversation/api/v1/workspaces/%s/message' % workspace_id
-    message_url1 = 'https://gateway.watsonplatform.net/conversation/api/v1/workspaces/%s/message?version=2016-09-20' % workspace_id
-    message_response = '{"context":{"conversation_id":"1b7b67c0-90ed-45dc-8508-9488bc483d5b","system":{"dialog_stack":["root"],"dialog_turn_counter":1,"dialog_request_counter":1}},"intents":[],"entities":[],"input":{}}'
+    message_url = '%s/workspaces/%s/message' % (base_url, workspace_id)
+    url1_str = '%s/workspaces/%s/message?version=2016-09-20'
+    message_url1 = url1_str % (base_url, workspace_id)
+    message_response = {"context": {
+                        "conversation_id":
+                            "1b7b67c0-90ed-45dc-8508-9488bc483d5b",
+                        "system": {"dialog_stack":
+                                   ["root"],
+                                   "dialog_turn_counter": 1,
+                                   "dialog_request_counter": 1}},
+                        "intents": [],
+                        "entities": [],
+                        "input": {}}
 
     responses.add(responses.POST, message_url,
-              body=message_response, status=200,
-              content_type='application/json')
+                  body=json.dumps(message_response),
+                  status=200,
+                  content_type='application/json')
 
-    message = conversation.message(workspace_id=workspace_id, message_input={'text': 'Turn on the lights'}, context=None)
+    message = conversation.message(workspace_id=workspace_id,
+                                   message_input={'text':
+                                                  'Turn on the lights'},
+                                   context=None)
 
     assert message is not None
     assert responses.calls[0].request.url == message_url1
-    assert responses.calls[0].response.text == message_response
+    assert responses.calls[0].response.text == json.dumps(message_response)
 
 
-    # test context
+# test context
     responses.add(responses.POST, message_url,
-              body=message_response, status=200,
-              content_type='application/json')
+                  body=message_response, status=200,
+                  content_type='application/json')
 
-    message = conversation.message(workspace_id=workspace_id, message_input={'text': 'Turn on the lights'}, context={'context': {'conversation_id':'1b7b67c0-90ed-45dc-8508-9488bc483d5b', 'system': {'dialog_stack':['root'], 'dialog_turn_counter':2, 'dialog_request_counter':1}}})
+    message_ctx = {'context':
+                   {'conversation_id': '1b7b67c0-90ed-45dc-8508-9488bc483d5b',
+                    'system': {
+                        'dialog_stack': ['root'],
+                        'dialog_turn_counter': 2,
+                        'dialog_request_counter': 1}}}
+    message = conversation.message(workspace_id=workspace_id,
+                                   message_input={'text':
+                                                  'Turn on the lights'},
+                                   context=json.dumps(message_ctx))
 
     assert message is not None
     assert responses.calls[1].request.url == message_url1
-    assert responses.calls[1].response.text == message_response
+    assert responses.calls[1].response.text == json.dumps(message_response)
 
     assert len(responses.calls) == 2