From 59f81845dd9d46c683dec78e5fde8d612a72051c Mon Sep 17 00:00:00 2001 From: derAnfaenger Date: Tue, 24 Oct 2017 13:15:51 +0200 Subject: [PATCH] zulip_bots: Update StateHandler API to behave dict-like. This matches the external StateHandler API with the embedded StateHandler API. --- .../bots/incrementor/incrementor.py | 27 +++++++---- .../bots/incrementor/test_incrementor.py | 1 + .../zulip_bots/bots/tictactoe/tictactoe.py | 48 +++++++++---------- .../zulip_bots/bots/virtual_fs/virtual_fs.py | 20 ++++---- zulip_bots/zulip_bots/lib.py | 26 +++++----- 5 files changed, 65 insertions(+), 57 deletions(-) diff --git a/zulip_bots/zulip_bots/bots/incrementor/incrementor.py b/zulip_bots/zulip_bots/bots/incrementor/incrementor.py index 9af704e..60e36c2 100644 --- a/zulip_bots/zulip_bots/bots/incrementor/incrementor.py +++ b/zulip_bots/zulip_bots/bots/incrementor/incrementor.py @@ -11,17 +11,24 @@ 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'] - else: - bot_handler.update_message(dict( - message_id = state['message_id'], - content = str(state['number']) - )) + 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 = storage.get('message_id'), + content = str(storage.get('number')) + )) handler_class = IncrementorHandler diff --git a/zulip_bots/zulip_bots/bots/incrementor/test_incrementor.py b/zulip_bots/zulip_bots/bots/incrementor/test_incrementor.py index 64f4cf1..a44c34a 100644 --- a/zulip_bots/zulip_bots/bots/incrementor/test_incrementor.py +++ b/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', diff --git a/zulip_bots/zulip_bots/bots/tictactoe/tictactoe.py b/zulip_bots/zulip_bots/bots/tictactoe/tictactoe.py index 8a0de94..88d244f 100644 --- a/zulip_bots/zulip_bots/bots/tictactoe/tictactoe.py +++ b/zulip_bots/zulip_bots/bots/tictactoe/tictactoe.py @@ -280,33 +280,33 @@ class ticTacToeHandler(object): for val in command_list: command += val original_sender = message['sender_email'] + 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) + storage.put(original_sender, user_board) + user_game = TicTacToeGame(user_board) if user_board else None - with bot_handler.storage.state({}) as mydict: - user_board = mydict.get(original_sender) - if (not user_board) and command == "new": - user_board = copy.deepcopy(initial_board) - mydict[original_sender] = user_board - user_game = TicTacToeGame(user_board) if user_board else None - - if command == 'new': - if user_game and not first_time(user_game.board): - return_content = "You're already playing a game! Type **@tictactoe help** or **@ttt help** to see valid inputs." - else: - return_content = "Welcome to tic-tac-toe! You'll be x's and I'll be o's. Your move first!\n" - return_content += TicTacToeGame.positions - 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] - return_content = "You've successfully quit the game." + if command == 'new': + if user_game and not first_time(user_game.board): + return_content = "You're already playing a game! Type **@tictactoe help** or **@ttt help** to see valid inputs." else: - return_content = "Hmm, I didn't understand your input. Type **@tictactoe help** or **@ttt help** to see valid inputs." + return_content = "Welcome to tic-tac-toe! You'll be x's and I'll be o's. Your move first!\n" + return_content += TicTacToeGame.positions + elif command == 'help': + return_content = TicTacToeGame.detailed_help_message + elif (user_game) and TicTacToeGame.check_validity(user_game, TicTacToeGame.sanitize_move(user_game, command)): + return_content = TicTacToeGame.tictactoe(user_game, user_board, command) + elif (user_game) and command == 'quit': + 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] + if "Game over" in return_content or "draw" in return_content: + storage.put(original_sender, None) bot_handler.send_message(dict( type = 'private', diff --git a/zulip_bots/zulip_bots/bots/virtual_fs/virtual_fs.py b/zulip_bots/zulip_bots/bots/virtual_fs/virtual_fs.py index 739c2c5..01141a8 100644 --- a/zulip_bots/zulip_bots/bots/virtual_fs/virtual_fs.py +++ b/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] - 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 = 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 + storage.put(recipient, fs) bot_handler.send_reply(message, msg) diff --git a/zulip_bots/zulip_bots/lib.py b/zulip_bots/zulip_bots/lib.py index 79eac9f..e12c33b 100644 --- a/zulip_bots/zulip_bots/lib.py +++ b/zulip_bots/zulip_bots/lib.py @@ -1,5 +1,6 @@ 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 + self.state_ = {} # type: Dict[Text, Text] + self.marshal = lambda obj: obj + self.demarshal = lambda obj: obj - def set_state(self, state): - # type: (Any) -> None - self.state_ = state + def put(self, key, value): + # type: (Text, Text) -> None + self.state_[key] = self.marshal(value) - def get_state(self): - # type: () -> Any - return self.state_ + def get(self, key): + # type: () -> Text + return self.demarshal(self.state_[key]) - @contextmanager - def state(self, default): - # type: (Any) -> Any - new_state = self.get_state() or default - yield new_state - self.set_state(new_state) + def contains(self, key): + # type: (Text) -> bool + return key in self.state_ class ExternalBotHandler(object): def __init__(self, client, root_dir):