mypy: Add annotations for virtual_fs.
This commit is contained in:
parent
a7f9c6e743
commit
f7f54d159f
|
@ -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.")
|
||||||
|
|
|
@ -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>"),
|
||||||
|
|
|
@ -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'
|
||||||
|
|
Loading…
Reference in a new issue