zulip_bots: Update StateHandler API to behave dict-like.
This matches the external StateHandler API with the embedded
StateHandler API.
MODIFY
zulip_bots/zulip_bots/bots/incrementor/incrementor.py
zulip_bots/zulip_bots/bots/incrementor/incrementor.py
@@ -11,16 +11,23 @@ class IncrementorHandler(object):
is @-mentioned, this number will be incremented in the same message.
'''
+ def initialize(self, bot_handler):
+ storage = bot_handler.storage
+ if not storage.contains('number') or not storage.contains('message_id'):
+ storage.put('number', 0)
+ storage.put('message_id', None)
+
def handle_message(self, message, bot_handler):
- with bot_handler.storage.state({'number': 0, 'message_id': None}) as state:
- state['number'] += 1
- if state['message_id'] is None:
- result = bot_handler.send_reply(message, str(state['number']))
- state['message_id'] = result['id']
+ storage = bot_handler.storage
+ num = storage.get('number')
+ storage.put('number', num + 1)
+ if storage.get('message_id') is None:
+ result = bot_handler.send_reply(message, str(storage.get('number')))
+ storage.put('message_id', result['id'])
else:
bot_handler.update_message(dict(
- message_id = state['message_id'],
- content = str(state['number'])
+ message_id = storage.get('message_id'),
+ content = str(storage.get('number'))
))

MODIFY
zulip_bots/zulip_bots/bots/incrementor/test_incrementor.py
zulip_bots/zulip_bots/bots/incrementor/test_incrementor.py
@@ -11,6 +11,7 @@ class TestIncrementorBot(BotTestCase):
bot_name = "incrementor"
def test_bot(self):
+ self.initialize_bot()
messages = [ # Template for message inputs to test, absent of message content
{
'type': 'stream',

MODIFY
zulip_bots/zulip_bots/bots/tictactoe/tictactoe.py
zulip_bots/zulip_bots/bots/tictactoe/tictactoe.py
@@ -280,12 +280,13 @@ class ticTacToeHandler(object):
for val in command_list:
command += val
original_sender = message['sender_email']
-
- with bot_handler.storage.state({}) as mydict:
- user_board = mydict.get(original_sender)
+ storage = bot_handler.storage
+ if not storage.contains(original_sender):
+ storage.put(original_sender, None)
+ user_board = storage.get(original_sender)
if (not user_board) and command == "new":
user_board = copy.deepcopy(initial_board)
- mydict[original_sender] = user_board
+ storage.put(original_sender, user_board)
user_game = TicTacToeGame(user_board) if user_board else None
if command == 'new':
@@ -297,16 +298,15 @@ class ticTacToeHandler(object):
elif command == 'help':
return_content = TicTacToeGame.detailed_help_message
elif (user_game) and TicTacToeGame.check_validity(user_game, TicTacToeGame.sanitize_move(user_game, command)):
- user_board = user_game.board
return_content = TicTacToeGame.tictactoe(user_game, user_board, command)
elif (user_game) and command == 'quit':
- del mydict[original_sender]
+ storage.put(original_sender, None)
return_content = "You've successfully quit the game."
else:
return_content = "Hmm, I didn't understand your input. Type **@tictactoe help** or **@ttt help** to see valid inputs."
if "Game over" in return_content or "draw" in return_content:
- del mydict[original_sender]
+ storage.put(original_sender, None)
bot_handler.send_message(dict(
type = 'private',

MODIFY
zulip_bots/zulip_bots/bots/virtual_fs/virtual_fs.py
zulip_bots/zulip_bots/bots/virtual_fs/virtual_fs.py
@@ -18,16 +18,16 @@ class VirtualFsHandler(object):
if isinstance(recipient, list): # If not a stream, then hash on list of emails
recipient = " ".join([x['email'] for x in recipient])
- with bot_handler.storage.state({}) as state:
- if recipient not in state:
- state[recipient] = fs_new()
- fs = state[recipient]
+ storage = bot_handler.storage
+ if not storage.contains(recipient):
+ storage.put(recipient, fs_new())
+ fs = storage.get(recipient)
if sender not in fs['user_paths']:
fs['user_paths'][sender] = '/'
fs, msg = fs_command(fs, sender, command)
prependix = '{}:\n'.format(sender)
msg = prependix + msg
- state[recipient] = fs
+ storage.put(recipient, fs)
bot_handler.send_reply(message, msg)

MODIFY
zulip_bots/zulip_bots/lib.py
zulip_bots/zulip_bots/lib.py
from __future__ import print_function
+import json
import logging
import os
import signal
@@ -54,22 +55,21 @@ class RateLimit(object):
class StateHandler(object):
def __init__(self):
# type: () -> None
- self.state_ = None # type: Any
-
- def set_state(self, state):
- # type: (Any) -> None
- self.state_ = state
-
- def get_state(self):
- # type: () -> Any
- return self.state_
-
- @contextmanager
- def state(self, default):
- # type: (Any) -> Any
- new_state = self.get_state() or default
- yield new_state
- self.set_state(new_state)
+ self.state_ = {} # type: Dict[Text, Text]
+ self.marshal = lambda obj: obj
+ self.demarshal = lambda obj: obj
+
+ def put(self, key, value):
+ # type: (Text, Text) -> None
+ self.state_[key] = self.marshal(value)
+
+ def get(self, key):
+ # type: () -> Text
+ return self.demarshal(self.state_[key])
+
+ def contains(self, key):
+ # type: (Text) -> bool
+ return key in self.state_
class ExternalBotHandler(object):
def __init__(self, client, root_dir):

zulip_bots: Update StateHandler API to behave dict-like.

This matches the external StateHandler API with the embedded
StateHandler API.