mypy: Add annotations for virtual_fs.

This commit is contained in:
fredfishgames 2017-12-08 11:14:55 +00:00 committed by showell
parent a7f9c6e743
commit f7f54d159f
3 changed files with 33 additions and 27 deletions

View file

@ -46,6 +46,8 @@ force_include = [
"zulip_bots/zulip_bots/bots/googlesearch/test_googlesearch.py", "zulip_bots/zulip_bots/bots/googlesearch/test_googlesearch.py",
"zulip_bots/zulip_bots/bots/help/help.py", "zulip_bots/zulip_bots/bots/help/help.py",
"zulip_bots/zulip_bots/bots/help/test_help.py", "zulip_bots/zulip_bots/bots/help/test_help.py",
"zulip_bots/zulip_bots/bots/virtual_fs/virtual_fs.py",
"zulip_bots/zulip_bots/bots/virtual_fs/test_virtual_fs.py",
] ]
parser = argparse.ArgumentParser(description="Run mypy on files tracked by git.") parser = argparse.ArgumentParser(description="Run mypy on files tracked by git.")

View file

@ -6,6 +6,8 @@ from __future__ import print_function
from zulip_bots.test_lib import BotTestCase from zulip_bots.test_lib import BotTestCase
from zulip_bots.lib import StateHandler from zulip_bots.lib import StateHandler
from typing import Any
class TestVirtualFsBot(BotTestCase): class TestVirtualFsBot(BotTestCase):
bot_name = "virtual_fs" bot_name = "virtual_fs"
help_txt = ('foo_sender@zulip.com:\n\nThis bot implements a virtual file system for a stream.\n' help_txt = ('foo_sender@zulip.com:\n\nThis bot implements a virtual file system for a stream.\n'
@ -24,7 +26,7 @@ class TestVirtualFsBot(BotTestCase):
'```\n' '```\n'
'Use commands like `@mention-bot help write` for more details on specific\ncommands.\n') 'Use commands like `@mention-bot help write` for more details on specific\ncommands.\n')
def test_commands_1(self): def test_commands_1(self) -> None:
expected = [ expected = [
("cd /home", "foo_sender@zulip.com:\nERROR: invalid path"), ("cd /home", "foo_sender@zulip.com:\nERROR: invalid path"),
("mkdir home", "foo_sender@zulip.com:\ndirectory created"), ("mkdir home", "foo_sender@zulip.com:\ndirectory created"),
@ -35,7 +37,7 @@ class TestVirtualFsBot(BotTestCase):
] ]
self.check_expected_responses(expected) self.check_expected_responses(expected)
def test_commands_2(self): def test_commands_2(self) -> None:
expected = [ expected = [
("help", self.help_txt), ("help", self.help_txt),
("help ls", "foo_sender@zulip.com:\nsyntax: ls <optional_path>"), ("help ls", "foo_sender@zulip.com:\nsyntax: ls <optional_path>"),

View file

@ -3,16 +3,18 @@
import re import re
import os import os
from typing import Any, Dict, List, Tuple, Callable, Set, Union
class VirtualFsHandler(object): class VirtualFsHandler(object):
META = { META = {
'name': 'VirtualFs', 'name': 'VirtualFs',
'description': 'Provides a simple, permanent file system to store and retrieve strings.', 'description': 'Provides a simple, permanent file system to store and retrieve strings.',
} }
def usage(self): def usage(self) -> str:
return get_help() return get_help()
def handle_message(self, message, bot_handler): def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None:
command = message['content'] command = message['content']
if command == "": if command == "":
command = "help" command = "help"
@ -37,7 +39,7 @@ class VirtualFsHandler(object):
bot_handler.send_reply(message, msg) bot_handler.send_reply(message, msg)
def get_help(): def get_help() -> str:
return ''' return '''
This bot implements a virtual file system for a stream. This bot implements a virtual file system for a stream.
The locations of text are persisted for the lifetime of the bot The locations of text are persisted for the lifetime of the bot
@ -59,7 +61,7 @@ Use commands like `@mention-bot help write` for more details on specific
commands. commands.
''' '''
def sample_conversation(): def sample_conversation() -> List[str]:
return [ return [
('cd /\nCurrent path: /\n\n'), ('cd /\nCurrent path: /\n\n'),
('cd /home\nERROR: invalid path\n\n'), ('cd /home\nERROR: invalid path\n\n'),
@ -118,7 +120,7 @@ REGEXES = dict(
some_text='(.+)', some_text='(.+)',
) )
def get_commands(): def get_commands() -> Dict[str, Tuple[Any, List[str]]]:
return { return {
'help': (fs_help, ['command']), 'help': (fs_help, ['command']),
'sample_conversation': (fs_sample_conversation, ['command']), 'sample_conversation': (fs_sample_conversation, ['command']),
@ -132,7 +134,7 @@ def get_commands():
'pwd': (fs_pwd, []), 'pwd': (fs_pwd, []),
} }
def fs_command(fs, user, cmd): def fs_command(fs: str, user: str, cmd: str) -> Tuple[str, Any]:
cmd = cmd.strip() cmd = cmd.strip()
if cmd == 'help': if cmd == 'help':
return fs, get_help() return fs, get_help()
@ -156,7 +158,7 @@ def fs_command(fs, user, cmd):
else: else:
return fs, 'ERROR: ' + syntax_help(cmd_name) return fs, 'ERROR: ' + syntax_help(cmd_name)
def syntax_help(cmd_name): def syntax_help(cmd_name: str) -> str:
commands = get_commands() commands = get_commands()
f, arg_names = commands[cmd_name] f, arg_names = commands[cmd_name]
arg_syntax = ' '.join('<' + a + '>' for a in arg_names) arg_syntax = ' '.join('<' + a + '>' for a in arg_names)
@ -166,20 +168,20 @@ def syntax_help(cmd_name):
cmd = cmd_name cmd = cmd_name
return 'syntax: {}'.format(cmd) return 'syntax: {}'.format(cmd)
def fs_new(): def fs_new() -> Dict[str, Any]:
fs = { fs = {
'/': directory([]), '/': directory([]),
'user_paths': dict() 'user_paths': dict()
} }
return fs return fs
def fs_help(fs, user, cmd_name): def fs_help(fs: Dict[str, Any], user: str, cmd_name: str) -> Tuple[Dict[str, Any], Any]:
return fs, syntax_help(cmd_name) return fs, syntax_help(cmd_name)
def fs_sample_conversation(fs, user, cmd_name): def fs_sample_conversation(fs: Dict[str, Any], user: str, cmd_name: str) -> Tuple[Dict[str, str], str]:
return fs, syntax_help(cmd_name) return fs, syntax_help(cmd_name)
def fs_mkdir(fs, user, fn): def fs_mkdir(fs: Dict[str, Any], user: str, fn: str) -> Tuple[Dict[str, Any], Any]:
path, msg = make_path(fs, user, fn) path, msg = make_path(fs, user, fn)
if msg: if msg:
return fs, msg return fs, msg
@ -196,7 +198,7 @@ def fs_mkdir(fs, user, fn):
msg = 'directory created' msg = 'directory created'
return new_fs, msg return new_fs, msg
def fs_ls(fs, user, fn): def fs_ls(fs: Dict[str, Any], user: str, fn: str) -> Tuple[Dict[str, Any], Any]:
if fn == '.' or fn == '': if fn == '.' or fn == '':
path = fs['user_paths'][user] path = fs['user_paths'][user]
else: else:
@ -214,12 +216,12 @@ def fs_ls(fs, user, fn):
msg = '\n'.join('* ' + nice_path(fs, path) for path in sorted(fns)) msg = '\n'.join('* ' + nice_path(fs, path) for path in sorted(fns))
return fs, msg return fs, msg
def fs_pwd(fs, user): def fs_pwd(fs: Dict[str, Any], user: str) -> Tuple[Dict[str, Any], Any]:
path = fs['user_paths'][user] path = fs['user_paths'][user]
msg = nice_path(fs, path) msg = nice_path(fs, path)
return fs, msg return fs, msg
def fs_rm(fs, user, fn): def fs_rm(fs: Dict[str, Any], user: str, fn: str) -> Tuple[Dict[str, Any], Any]:
path, msg = make_path(fs, user, fn) path, msg = make_path(fs, user, fn)
if msg: if msg:
return fs, msg return fs, msg
@ -236,7 +238,7 @@ def fs_rm(fs, user, fn):
msg = 'removed' msg = 'removed'
return new_fs, msg return new_fs, msg
def fs_rmdir(fs, user, fn): def fs_rmdir(fs: Dict[str, Any], user: str, fn: str) -> Tuple[Dict[str, Any], Any]:
path, msg = make_path(fs, user, fn) path, msg = make_path(fs, user, fn)
if msg: if msg:
return fs, msg return fs, msg
@ -256,7 +258,7 @@ def fs_rmdir(fs, user, fn):
msg = 'removed' msg = 'removed'
return new_fs, msg return new_fs, msg
def fs_write(fs, user, fn, content): def fs_write(fs: Dict[str, Any], user: str, fn: str, content: str) -> Tuple[Dict[str, Any], Any]:
path, msg = make_path(fs, user, fn) path, msg = make_path(fs, user, fn)
if msg: if msg:
return fs, msg return fs, msg
@ -274,7 +276,7 @@ def fs_write(fs, user, fn, content):
msg = 'file written' msg = 'file written'
return new_fs, msg return new_fs, msg
def fs_read(fs, user, fn): def fs_read(fs: Dict[str, Any], user: str, fn: str) -> Tuple[Dict[str, Any], Any]:
path, msg = make_path(fs, user, fn) path, msg = make_path(fs, user, fn)
if msg: if msg:
return fs, msg return fs, msg
@ -287,7 +289,7 @@ def fs_read(fs, user, fn):
val = fs[path]['content'] val = fs[path]['content']
return fs, val return fs, val
def fs_cd(fs, user, fn): def fs_cd(fs: Dict[str, Any], user: str, fn: str) -> Tuple[Dict[str, Any], Any]:
if len(fn) > 1 and fn[-1] == '/': if len(fn) > 1 and fn[-1] == '/':
fn = fn[:-1] fn = fn[:-1]
path = fn if len(fn) > 0 and fn[0] == '/' else make_path(fs, user, fn)[0] path = fn if len(fn) > 0 and fn[0] == '/' else make_path(fs, user, fn)[0]
@ -300,7 +302,7 @@ def fs_cd(fs, user, fn):
fs['user_paths'][user] = path fs['user_paths'][user] = path
return fs, "Current path: {}".format(nice_path(fs, path)) return fs, "Current path: {}".format(nice_path(fs, path))
def make_path(fs, user, leaf): def make_path(fs: Dict[str, Any], user: str, leaf: str) -> List[str]:
if leaf == '/': if leaf == '/':
return ['/', ''] return ['/', '']
if leaf.endswith('/'): if leaf.endswith('/'):
@ -311,9 +313,9 @@ def make_path(fs, user, leaf):
if not path.endswith('/'): if not path.endswith('/'):
path += '/' path += '/'
path += leaf path += leaf
return path, '' return [path, '']
def nice_path(fs, path): def nice_path(fs: Dict[str, Any], path: str) -> str:
path_nice = path path_nice = path
slash = path.rfind('/') slash = path.rfind('/')
if path not in fs: if path not in fs:
@ -324,20 +326,20 @@ def nice_path(fs, path):
path_nice = '{}/'.format(path) path_nice = '{}/'.format(path)
return path_nice return path_nice
def get_directory(path): def get_directory(path: str) -> str:
slash = path.rfind('/') slash = path.rfind('/')
if slash == 0: if slash == 0:
return '/' return '/'
else: else:
return path[:slash] return path[:slash]
def directory(fns): def directory(fns: Union[Set[str], List[Any]]) -> Dict[str, Union[str, List[Any]]]:
return dict(kind='dir', fns=list(fns)) return dict(kind='dir', fns=list(fns))
def text_file(content): def text_file(content: str) -> Dict[str, str]:
return dict(kind='text', content=content) return dict(kind='text', content=content)
def is_directory(fs, fn): def is_directory(fs: Dict[str, Any], fn: str) -> bool:
if fn not in fs: if fn not in fs:
return False return False
return fs[fn]['kind'] == 'dir' return fs[fn]['kind'] == 'dir'