Skip to content

Commit

Permalink
Rename 'context' to 'chatbot'
Browse files Browse the repository at this point in the history
This variable is being renamed to help stop developers from being
confused. The new name is more accurate and descriptive.
  • Loading branch information
gunthercox committed Nov 26, 2016
1 parent 379992e commit b08e61b
Show file tree
Hide file tree
Showing 17 changed files with 101 additions and 93 deletions.
21 changes: 17 additions & 4 deletions chatterbot/adapters/adapter.py
Expand Up @@ -8,14 +8,27 @@ class Adapter(object):

def __init__(self, **kwargs):
self.logger = kwargs.get('logger', logging.getLogger(__name__))
self.context = None
self.chatbot = None

def set_context(self, context):
self.context = context
def set_chatbot(self, chatbot):
"""
Gives the adapter access to an instance of the ChatBot class.
"""
self.chatbot = chatbot

class AdapterMethodNotImplementedError(NotImplementedError):
"""
An exception to be raised when an adapter method has not been implemented.
Typically this indicates that the developer is expected to implement the
method in a subclass.
"""

def __init__(self, message='This method must be overridden in a subclass method.'):
def __init__(self, message=None):
"""
Set the message for the esception.
"""
if not message:
message = 'This method must be overridden in a subclass method.'
self.message = message

def __str__(self):
Expand Down
4 changes: 2 additions & 2 deletions chatterbot/adapters/input/hipchat.py
Expand Up @@ -75,8 +75,8 @@ def process_input(self, statement):

new_message = False

input_statement = self.context.get_last_input_statement()
response_statement = self.context.get_last_response_statement()
input_statement = self.chatbot.get_last_input_statement()
response_statement = self.chatbot.get_last_response_statement()

if input_statement:
last_message_id = input_statement.extra_data.get(
Expand Down
2 changes: 1 addition & 1 deletion chatterbot/adapters/input/input_adapter.py
Expand Up @@ -21,7 +21,7 @@ def process_input_statement(self, *args, **kwargs):
input_statement = self.process_input(*args, **kwargs)
self.logger.info('Recieved input statement: {}'.format(input_statement.text))

existing_statement = self.context.storage.find(input_statement.text)
existing_statement = self.chatbot.storage.find(input_statement.text)

if existing_statement:
self.logger.info('"{}" is a known statement'.format(input_statement.text))
Expand Down
24 changes: 12 additions & 12 deletions chatterbot/adapters/logic/base_match.py
Expand Up @@ -9,27 +9,27 @@ class BaseMatchAdapter(LogicAdapter):
"""

@property
def has_storage_context(self):
def has_storage(self):
"""
Return true if the adapter has access to the storage adapter context.
Return true if the adapter has access to the chatbot's storage adapter.
"""
return self.context and self.context.storage
return self.chatbot and self.chatbot.storage

def get(self, input_statement):
"""
Takes a statement string and a list of statement strings.
Returns the closest matching statement from the list.
"""
statement_list = self.context.storage.get_response_statements()
statement_list = self.chatbot.storage.get_response_statements()

if not statement_list:
if self.has_storage_context:
if self.has_storage:
# Use a randomly picked statement
self.logger.info(
'No statements have known responses. ' +
'Choosing a random response to return.'
)
return 0, self.context.storage.get_random()
return 0, self.chatbot.storage.get_random()
else:
raise self.EmptyDatasetException()

Expand All @@ -48,10 +48,10 @@ def get(self, input_statement):

def can_process(self, statement):
"""
Check that the storage context is available and there
is at least one statement in the database.
Check that the chatbot's storage adapter is available to the logic adapter
and there is at least one statement in the database.
"""
return self.has_storage_context and self.context.storage.count()
return self.has_storage and self.chatbot.storage.count()

def process(self, input_statement):

Expand All @@ -62,10 +62,10 @@ def process(self, input_statement):
))

# Save any updates made to the statement by the logic adapter
self.context.storage.update(closest_match)
self.chatbot.storage.update(closest_match)

# Get all statements that are in response to the closest match
response_list = self.context.storage.filter(
response_list = self.chatbot.storage.filter(
in_response_to__contains=closest_match.text
)

Expand All @@ -78,7 +78,7 @@ def process(self, input_statement):
response = self.select_response(input_statement, response_list)
self.logger.info('Response selected. Using "{}"'.format(response.text))
else:
response = self.context.storage.get_random()
response = self.chatbot.storage.get_random()
self.logger.info(
'No response to "{}" found. Selecting a random response.'.format(
closest_match.text
Expand Down
12 changes: 6 additions & 6 deletions chatterbot/adapters/logic/multi_adapter.py
@@ -1,13 +1,13 @@
from __future__ import unicode_literals
from .logic_adapter import LogicAdapter
from collections import Counter
from .logic_adapter import LogicAdapter


class MultiLogicAdapter(LogicAdapter):
"""
MultiLogicAdapter allows ChatterBot to use multiple logic
adapters. It has methods that allow ChatterBot to add an
adapter, set the context, and process an input statement
adapter, set the chat bot, and process an input statement
to get a response.
"""

Expand Down Expand Up @@ -84,11 +84,11 @@ def add_adapter(self, adapter):
"""
self.adapters.append(adapter)

def set_context(self, context):
def set_chatbot(self, chatbot):
"""
Set the context for each of the contained logic adapters.
Set the chatbot for each of the contained logic adapters.
"""
super(MultiLogicAdapter, self).set_context(context)
super(MultiLogicAdapter, self).set_chatbot(chatbot)

for adapter in self.adapters:
adapter.set_context(context)
adapter.set_chatbot(chatbot)
2 changes: 1 addition & 1 deletion chatterbot/adapters/logic/no_knowledge_adapter.py
Expand Up @@ -18,7 +18,7 @@ def process(self, statement):
Otherwise, a confidence of 0 should be returned.
"""

if self.context.storage.count():
if self.chatbot.storage.count():
return 0, statement

return 1, statement
2 changes: 1 addition & 1 deletion chatterbot/adapters/output/hipchat.py
Expand Up @@ -58,7 +58,7 @@ def process_response(self, statement, confidence=None):
data = self.send_message(self.hipchat_room, statement.text)

# Update the output statement with the message id
self.context.recent_statements[-1][1].add_extra_data(
self.chatbot.recent_statements[-1][1].add_extra_data(
'hipchat_message_id', data['id']
)

Expand Down
12 changes: 6 additions & 6 deletions chatterbot/chatterbot.py
Expand Up @@ -56,12 +56,12 @@ def __init__(self, name, **kwargs):
for adapter in logic_adapters:
self.add_logic_adapter(adapter, **kwargs)

# Share context information such as the name, the current conversation,
# or access to other adapters with each of the adapters
self.storage.set_context(self)
self.logic.set_context(self)
self.input.set_context(self)
self.output.set_context(self)
# Add the chatbot instance to each adapter to share information such as
# the name, the current conversation, or other adapters
self.storage.set_chatbot(self)
self.logic.set_chatbot(self)
self.input.set_chatbot(self)
self.output.set_chatbot(self)

# Use specified trainer or fall back to the default
trainer = kwargs.get('trainer', 'chatterbot.trainers.Trainer')
Expand Down
13 changes: 9 additions & 4 deletions docs/adapters/index.rst
Expand Up @@ -27,12 +27,17 @@ Adapters types
3. Output adapters - Provide methods that allow ChatterBot to return a response to a defined data source.
4. Logic adapters - Define the logic that ChatterBot uses to respond to input it receives.

Context
-------
Accessing the chatbot instance
-------------------------------

When ChatterBot initializes each adapter, it sets an attribute named 'context'. The context variable makes it possible for each adapter to have access to all of the other adapters being used. Perhaps two input and output adapters need to share some information or maybe you want to give your logic adapter direct access to the storage adapter. These are just a few cases where this functionality is useful.
When ChatterBot initializes each adapter, it sets an attribute named :code:`chatbot`.
The chatbot variable makes it possible for each adapter to have access to all of the other adapters being used.
Suppose two input and output adapters need to share some information or perhaps you want to give your logic adapter
direct access to the storage adapter. These are just a few cases where this functionality is useful.

Each adapter can be accessed on the context object from within an adapter by referencing `self.context`. Then, `self.context.storage` refers to the storage adapter, `self.context.input` refers to the input adapter, `self.context.output` refers to the current output adapter, and `self.context.logic` refers to the list of logic adapters.
Each adapter can be accessed on the chatbot object from within an adapter by referencing `self.chatbot`.
Then, :code:`self.chatbot.storage` refers to the storage adapter, :code:`self.chatbot.input` refers to the input adapter,
:code:`self.chatbot.output` refers to the current output adapter, and :code:`self.chatbot.logic` refers to the logic adapters.

Adapter defaults
----------------
Expand Down
2 changes: 1 addition & 1 deletion tests/input_adapter_tests/test_input_adapter.py
Expand Up @@ -23,7 +23,7 @@ def test_process_response_statement(self):
self.adapter.process_input_statement()

def test_process_response_statement_initialized(self):
self.adapter.context = self.chatbot
self.adapter.chatbot = self.chatbot
self.adapter.process_input = lambda *args, **kwargs: Statement('Hi')
response = self.adapter.process_input_statement()
self.assertEqual(response, 'Hi')
22 changes: 11 additions & 11 deletions tests/logic_adapter_tests/test_closest_match.py
Expand Up @@ -5,7 +5,7 @@
from chatterbot.conversation import Statement, Response


class MockContext(object):
class MockChatBot(object):
def __init__(self):
self.storage = StorageAdapter()

Expand All @@ -19,11 +19,11 @@ class ClosestMatchAdapterTests(TestCase):
def setUp(self):
self.adapter = ClosestMatchAdapter()

# Add a mock storage adapter to the context
self.adapter.set_context(MockContext())
# Add a mock chatbot to the logic adapter
self.adapter.set_chatbot(MockChatBot())

def test_no_choices(self):
self.adapter.context.storage.filter = MagicMock(return_value=[])
self.adapter.chatbot.storage.filter = MagicMock(return_value=[])

statement = Statement("What is your quest?")

Expand All @@ -44,7 +44,7 @@ def test_get_closest_statement(self):
Statement("Yuck, black licorice jelly beans.", in_response_to=[Response("What is the meaning of life?")]),
Statement("I hear you are going on a quest?", in_response_to=[Response("Who do you love?")]),
]
self.adapter.context.storage.filter = MagicMock(return_value=possible_choices)
self.adapter.chatbot.storage.filter = MagicMock(return_value=possible_choices)

statement = Statement("What is your quest?")

Expand All @@ -56,7 +56,7 @@ def test_confidence_exact_match(self):
possible_choices = [
Statement("What is your quest?", in_response_to=[Response("What is your quest?")])
]
self.adapter.context.storage.filter = MagicMock(return_value=possible_choices)
self.adapter.chatbot.storage.filter = MagicMock(return_value=possible_choices)

statement = Statement("What is your quest?")
confidence, match = self.adapter.get(statement)
Expand All @@ -67,7 +67,7 @@ def test_confidence_half_match(self):
possible_choices = [
Statement("xxyy", in_response_to=[Response("xxyy")])
]
self.adapter.context.storage.filter = MagicMock(return_value=possible_choices)
self.adapter.chatbot.storage.filter = MagicMock(return_value=possible_choices)

statement = Statement("wwxx")
confidence, match = self.adapter.get(statement)
Expand All @@ -78,7 +78,7 @@ def test_confidence_no_match(self):
possible_choices = [
Statement("xxx", in_response_to=[Response("xxx")])
]
self.adapter.context.storage.filter = MagicMock(return_value=possible_choices)
self.adapter.chatbot.storage.filter = MagicMock(return_value=possible_choices)

statement = Statement("yyy")
confidence, match = self.adapter.get(statement)
Expand All @@ -91,11 +91,11 @@ def test_no_known_responses(self):
In this case a random response will be returned, but the confidence
should be zero because it is a random choice.
"""
self.adapter.context.storage.update = MagicMock()
self.adapter.context.storage.filter = MagicMock(
self.adapter.chatbot.storage.update = MagicMock()
self.adapter.chatbot.storage.filter = MagicMock(
return_value=[]
)
self.adapter.context.storage.get_random = MagicMock(
self.adapter.chatbot.storage.get_random = MagicMock(
return_value=Statement("Random")
)

Expand Down
32 changes: 12 additions & 20 deletions tests/logic_adapter_tests/test_closest_meaning.py
Expand Up @@ -3,27 +3,19 @@
from chatterbot.adapters.logic import ClosestMeaningAdapter
from chatterbot.adapters.storage import StorageAdapter
from chatterbot.conversation import Statement, Response


class MockContext(object):
def __init__(self):
self.storage = StorageAdapter()

self.storage.get_random = Mock(
side_effect=ClosestMeaningAdapter.EmptyDatasetException()
)
from tests.logic_adapter_tests.test_closest_match import MockChatBot


class ClosestMeaningAdapterTests(TestCase):

def setUp(self):
self.adapter = ClosestMeaningAdapter()

# Add a mock storage adapter to the context
self.adapter.set_context(MockContext())
# Add a mock storage adapter to the logic adapter
self.adapter.set_chatbot(MockChatBot())

def test_no_choices(self):
self.adapter.context.storage.filter = MagicMock(return_value=[])
self.adapter.chatbot.storage.filter = MagicMock(return_value=[])
statement = Statement('Hello')

with self.assertRaises(ClosestMeaningAdapter.EmptyDatasetException):
Expand All @@ -40,7 +32,7 @@ def test_get_closest_statement(self):
Statement('This is a beautiful swamp.', in_response_to=[Response('This is a beautiful swamp.')]),
Statement('It smells like a swamp.', in_response_to=[Response('It smells like a swamp.')])
]
self.adapter.context.storage.filter = MagicMock(
self.adapter.chatbot.storage.filter = MagicMock(
return_value=possible_choices
)

Expand All @@ -55,7 +47,7 @@ def test_different_punctuation(self):
Statement('Are you good?'),
Statement('You are good')
]
self.adapter.context.storage.get_response_statements = MagicMock(
self.adapter.chatbot.storage.get_response_statements = MagicMock(
return_value=possible_choices
)

Expand All @@ -70,15 +62,15 @@ def test_no_known_responses(self):
In this case a random response will be returned, but the confidence
should be zero because it is a random choice.
"""
self.adapter.context.storage.update = MagicMock()
self.adapter.context.storage.filter = MagicMock(
self.adapter.chatbot.storage.update = MagicMock()
self.adapter.chatbot.storage.filter = MagicMock(
return_value=[]
)
self.adapter.context.storage.get_random = MagicMock(
return_value=Statement("Random")
self.adapter.chatbot.storage.get_random = MagicMock(
return_value=Statement('Random')
)

confidence, match = self.adapter.process(Statement("Blah"))
confidence, match = self.adapter.process(Statement('Blah'))

self.assertEqual(confidence, 0)
self.assertEqual(match.text, "Random")
self.assertEqual(match.text, 'Random')
7 changes: 3 additions & 4 deletions tests/logic_adapter_tests/test_data_cache.py
@@ -1,8 +1,7 @@
import os
from tests.base_case import ChatBotTestCase
from chatterbot.adapters.logic import LogicAdapter
from chatterbot.conversation import Statement
from chatterbot.trainers import ListTrainer
import os


class DummyMutatorLogicAdapter(LogicAdapter):
Expand All @@ -14,7 +13,7 @@ class DummyMutatorLogicAdapter(LogicAdapter):
def process(self, statement):
statement.add_extra_data('pos_tags', 'NN')

self.context.storage.update(statement)
self.chatbot.storage.update(statement)

return 1, statement

Expand All @@ -25,7 +24,7 @@ def setUp(self):
super(DataCachingTests, self).setUp()

self.chatbot.logic = DummyMutatorLogicAdapter()
self.chatbot.logic.set_context(self.chatbot)
self.chatbot.logic.set_chatbot(self.chatbot)

self.chatbot.set_trainer(ListTrainer)

Expand Down

0 comments on commit b08e61b

Please sign in to comment.