summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerry Howe <terrylhowe@gmail.com>2013-10-30 17:25:59 -0600
committerTerry Howe <terrylhowe@gmail.com>2013-10-30 17:25:59 -0600
commit5d33c97404e5661bca62b1e9907740ee83cec3c6 (patch)
tree18b4566669b54d765c189143558093ad3c32a3c9
parent5be07a22eb8197d805af7954316f8c29e3a66c3f (diff)
downloadcliff-5d33c97404e5661bca62b1e9907740ee83cec3c6.tar.gz
various python code optimizations; shuffle I/O to shell classes
-rw-r--r--cliff/complete.py163
-rw-r--r--cliff/tests/test_complete.py156
2 files changed, 150 insertions, 169 deletions
diff --git a/cliff/complete.py b/cliff/complete.py
index 24cb7e4..c31c659 100644
--- a/cliff/complete.py
+++ b/cliff/complete.py
@@ -15,42 +15,26 @@ class CompleteDictionary:
self._dictionary = {}
def add_command(self, command, actions):
- optstr = ""
+ optstr = ' '.join(opt for action in actions
+ for opt in action.option_strings)
dicto = self._dictionary
- for action in actions:
- for opt in action.option_strings:
- if optstr:
- optstr += " " + opt
- else:
- optstr += opt
last = None
lastsubcmd = None
- for subcmd in command:
- if subcmd not in dicto:
- dicto[subcmd] = {}
- last = dicto
- lastsubcmd = subcmd
- dicto = dicto[subcmd]
- last[lastsubcmd] = optstr
+ for subcmd in command[:-1]:
+ dicto = dicto.setdefault(subcmd, {})
+ dicto[command[-1]] = optstr
def get_commands(self):
- cmdo = ""
- keys = sorted(self._dictionary.keys())
- for cmd in keys:
- if cmdo == "":
- cmdo += cmd
- else:
- cmdo += " " + cmd
- return cmdo
+ return ' '.join(k for k in sorted(self._dictionary.keys()))
def _get_data_recurse(self, dictionary, path):
ray = []
keys = sorted(dictionary.keys())
for cmd in keys:
if path == "":
- name = str(cmd)
+ name = cmd
else:
- name = path + "_" + str(cmd)
+ name = path + "_" + cmd
value = dictionary[cmd]
if isinstance(value, str):
ray.append((name, value))
@@ -64,11 +48,25 @@ class CompleteDictionary:
return sorted(self._get_data_recurse(self._dictionary, ""))
-class CompleteNoCode:
+class CompleteShellBase(object):
+ """ base class for bash completion generation
+ """
+ def __init__(self, name, output):
+ self.name = str(name)
+ self.output = output
+
+ def write(self, cmdo, data):
+ self.output.write(self.get_header())
+ self.output.write(" cmds='{0}'\n".format(cmdo))
+ for datum in data:
+ self.output.write(' cmds_{0}=\'{1}\'\n'.format(*datum))
+ self.output.write(self.get_trailer())
+
+class CompleteNoCode(CompleteShellBase):
"""completion with no code
"""
- def __init__(self, name):
- self.name = name
+ def __init__(self, name, output):
+ super(CompleteNoCode, self).__init__(name, output)
def get_header(self):
return ''
@@ -77,60 +75,62 @@ class CompleteNoCode:
return ''
-class CompleteBash:
+class CompleteBash(CompleteShellBase):
"""completion for bash
"""
- def __init__(self, name):
- self.name = str(name)
+ def __init__(self, name, output):
+ super(CompleteBash, self).__init__(name, output)
def get_header(self):
- return ('_' + self.name + '()\n\
-{\n\
- local cur prev words\n\
- COMPREPLY=()\n\
- _get_comp_words_by_ref -n : cur prev words\n\
-\n\
- # Command data:\n')
+ return ('_' + self.name + """()
+{
+ local cur prev words
+ COMPREPLY=()
+ _get_comp_words_by_ref -n : cur prev words
+
+ # Command data:
+""")
def get_trailer(self):
- return ('\
-\n\
- cmd=""\n\
- words[0]=""\n\
- completed="${cmds}" \n\
- for var in "${words[@]:1}"\n\
- do\n\
- if [[ ${var} == -* ]] ; then\n\
- break\n\
- fi\n\
- if [ -z "${cmd}" ] ; then\n\
- proposed="${var}"\n\
- else\n\
- proposed="${cmd}_${var}"\n\
- fi\n\
- local i="cmds_${proposed}"\n\
- local comp="${!i}"\n\
- if [ -z "${comp}" ] ; then\n\
- break\n\
- fi\n\
- if [[ ${comp} == -* ]] ; then\n\
- if [[ ${cur} != -* ]] ; then\n\
- completed=""\n\
- break\n\
- fi\n\
- fi\n\
- cmd="${proposed}"\n\
- completed="${comp}"\n\
- done\n\
-\n\
- if [ -z "${completed}" ] ; then\n\
- COMPREPLY=( $( compgen -f -- "$cur" ) $( compgen -d -- "$cur" ) )\n\
- else\n\
- COMPREPLY=( $(compgen -W "${completed}" -- ${cur}) )\n\
- fi\n\
- return 0\n\
-}\n\
-complete -F _' + self.name + ' ' + self.name + '\n')
+ return (
+"""
+
+ cmd=""
+ words[0]=""
+ completed="${cmds}"
+ for var in "${words[@]:1}"
+ do
+ if [[ ${var} == -* ]] ; then
+ break
+ fi
+ if [ -z "${cmd}" ] ; then
+ proposed="${var}"
+ else
+ proposed="${cmd}_${var}"
+ fi
+ local i="cmds_${proposed}"
+ local comp="${!i}"
+ if [ -z "${comp}" ] ; then
+ break
+ fi
+ if [[ ${comp} == -* ]] ; then
+ if [[ ${cur} != -* ]] ; then
+ completed=""
+ break
+ fi
+ fi
+ cmd="${proposed}"
+ completed="${comp}"
+ done
+
+ if [ -z "${completed}" ] ; then
+ COMPREPLY=( $( compgen -f -- "$cur" ) $( compgen -d -- "$cur" ) )
+ else
+ COMPREPLY=( $(compgen -W "${completed}" -- ${cur}) )
+ fi
+ return 0
+}
+complete -F _""" + self.name + ' ' + self.name + '\n')
class CompleteCommand(command.Command):
@@ -175,22 +175,15 @@ class CompleteCommand(command.Command):
else:
name = self.app.NAME
if parsed_args.shell == "none":
- shell = CompleteNoCode(name)
+ shell = CompleteNoCode(name, self.app.stdout)
else:
- shell = CompleteBash(name)
-
- self.app.stdout.write(shell.get_header())
+ shell = CompleteBash(name, self.app.stdout)
dicto = CompleteDictionary()
for cmd in self.app.command_manager:
command = cmd[0].split()
dicto.add_command(command, self.get_actions(command))
- cmdo = dicto.get_commands()
- self.app.stdout.write(" cmds='{0}'\n".format(cmdo))
- for datum in dicto.get_data():
- self.app.stdout.write(' cmds_{0}=\'{1}\'\n'.format(*datum))
-
- self.app.stdout.write(shell.get_trailer())
+ shell.write(dicto.get_commands(), dicto.get_data())
return 0
diff --git a/cliff/tests/test_complete.py b/cliff/tests/test_complete.py
index 23775c0..eecf48c 100644
--- a/cliff/tests/test_complete.py
+++ b/cliff/tests/test_complete.py
@@ -2,12 +2,14 @@
"""
import mock
-import os
+from cliff.app import App
+from cliff.command import Command
+from cliff.commandmanager import CommandManager
from cliff import complete
-def test_add_command():
+def test_complete_dictionary():
sot = complete.CompleteDictionary()
sot.add_command("image delete".split(),
[mock.Mock(option_strings=["1"])])
@@ -43,48 +45,38 @@ class FakeStdout:
result = result + line
return result
-def create_complete_command_mocks():
- app = mock.Mock(name="app")
- app_args = mock.Mock(name="app_args")
- # actions
- action_one = mock.Mock(name="action_one")
- action_one.option_strings = ["Eolus"]
- action_two = mock.Mock(name="action_two")
- action_two.option_strings = ["Wilson", "Sunlight"]
- actions = [action_one, action_two]
- # get_optional_actions
- get_optional_actions = mock.Mock(name="get_optional_actions")
- get_optional_actions.return_value = actions
- # cmd_parser
- cmd_parser = mock.Mock(name="cmd_parser")
- cmd_parser._get_optional_actions = get_optional_actions
- # get_parser
- get_parser = mock.Mock(name="get_parser")
- get_parser.return_value = cmd_parser
- # cmd_factory_init
- cmd_factory_init = mock.Mock("cmd_factory_init")
- cmd_factory_init.get_parser = get_parser
- # cmd_factory
- cmd_factory = mock.Mock(name="cmd_factory")
- cmd_factory.return_value = cmd_factory_init
- # find_command
- cmd_name = "yale"
- search_args = "search_args"
- find_command = mock.Mock(name="find_command")
- find_command.return_value = (cmd_factory, cmd_name, search_args)
- # command_manager
- commands = [["image create"], ["server meta delete"], ["server ssh"]]
- command_manager = mock.MagicMock()
- command_manager.__iter__.return_value = iter(commands)
- command_manager.find_command = find_command
- app.command_manager = command_manager
- app.NAME = "openstack"
- app.interactive_mode = False
- app.stdout = FakeStdout()
- return (complete.CompleteCommand(app, app_args), app, actions, cmd_factory_init)
+def given_cmdo_data():
+ cmdo = "image server"
+ data = [("image", "create"),
+ ("image_create", "--eolus"),
+ ("server", "meta ssh"),
+ ("server_meta_delete", "--wilson"),
+ ("server_ssh", "--sunlight")]
+ return cmdo, data
-def check_parser(cmd, args, verify_args):
- cmd_parser = cmd.get_parser('check_parser')
+def then_data(content):
+ assert " cmds='image server'\n" in content
+ assert " cmds_image='create'\n" in content
+ assert " cmds_image_create='--eolus'\n" in content
+ assert " cmds_server='meta ssh'\n" in content
+ assert " cmds_server_meta_delete='--wilson'\n" in content
+ assert " cmds_server_ssh='--sunlight'\n" in content
+
+def test_complete_no_code():
+ output = FakeStdout()
+ sot = complete.CompleteNoCode("doesNotMatter", output)
+ sot.write(*given_cmdo_data())
+ then_data(output.content)
+
+def test_complete_bash():
+ output = FakeStdout()
+ sot = complete.CompleteBash("openstack", output)
+ sot.write(*given_cmdo_data())
+ then_data(output.content)
+ assert "_openstack()\n" in output.content[0]
+ assert "complete -F _openstack openstack\n" in output.content[-1]
+
+def then_parser(cmd, args, verify_args):
parsed_args = cmd_parser.parse_args(args)
for av in verify_args:
attr, value = av
@@ -92,48 +84,44 @@ def check_parser(cmd, args, verify_args):
assert attr in parsed_args
assert getattr(parsed_args, attr) == value
-def test_parser_nothing():
- sot, app, actions, cmd_factory_init = create_complete_command_mocks()
- check_parser(sot, [], [('name', None), ('shell', 'bash')])
-
-def test_parser_no_code():
- sot, app, actions, cmd_factory_init = create_complete_command_mocks()
- check_parser(sot, ["--shell", "none", "--name", "foo"],
- [('name', 'foo'), ('shell', 'none')])
-
-def test_get_actions():
- sot, app, actions, cmd_factory_init = create_complete_command_mocks()
- result = sot.get_actions("yale")
- cmd_factory_init.get_parser.assert_called_with('openstack yale')
- assert actions == result
+def test_complete_command_parser():
+ sot = complete.CompleteCommand(mock.Mock(), mock.Mock())
+ parser = sot.get_parser('nothing')
+ assert "nothing" == parser.prog
+ assert "print bash completion command\n " == parser.description
+
+def given_complete_command():
+ cmd_mgr = CommandManager('cliff.tests')
+ app = App('testing', '1', cmd_mgr, stdout=FakeStdout())
+ sot = complete.CompleteCommand(app, mock.Mock())
+ cmd_mgr.add_command('complete', complete.CompleteCommand)
+ return sot, app, cmd_mgr
+
+def then_actions_equal(actions):
+ optstr = ' '.join(opt for action in actions
+ for opt in action.option_strings)
+ assert '-h --help --name --shell' == optstr
+
+def test_complete_command_get_actions():
+ sot, app, cmd_mgr = given_complete_command()
+ app.interactive_mode = False
+ actions = sot.get_actions(["complete"])
+ then_actions_equal(actions)
-def test_get_actions_interactive():
- sot, app, actions, cmd_factory_init = create_complete_command_mocks()
+def test_complete_command_get_actions_interactive():
+ sot, app, cmd_mgr = given_complete_command()
app.interactive_mode = True
- result = sot.get_actions("yale")
- cmd_factory_init.get_parser.assert_called_with('yale')
- assert actions == result
-
-def verify_data(content):
- assert " cmds='image server'\n" in content
- assert " cmds_image='create'\n" in content
- assert " cmds_image_create='Eolus Wilson Sunlight'\n" in content
- assert " cmds_server='meta ssh'\n" in content
- assert " cmds_server_meta_delete='Eolus Wilson Sunlight'\n" in content
- assert " cmds_server_ssh='Eolus Wilson Sunlight'\n" in content
-
-def test_take_action_nocode():
- sot, app, actions, cmd_factory_init = create_complete_command_mocks()
- parsed_args = mock.Mock()
- parsed_args.shell = "none"
- sot.take_action(parsed_args)
- verify_data(app.stdout.content)
+ actions = sot.get_actions(["complete"])
+ then_actions_equal(actions)
-def test_take_action_code():
- sot, app, actions, cmd_factory_init = create_complete_command_mocks()
+def test_complete_command_take_action():
+ sot, app, cmd_mgr = given_complete_command()
parsed_args = mock.Mock()
- parsed_args.name = "openstack"
- sot.take_action(parsed_args)
- verify_data(app.stdout.content)
- assert "_openstack()\n" in app.stdout.content[0]
- assert "complete -F _openstack openstack\n" in app.stdout.content[-1]
+ parsed_args.name = "test_take"
+ content = app.stdout.content
+ assert 0 == sot.take_action(parsed_args)
+ assert "_test_take()\n" in content[0]
+ assert "complete -F _test_take test_take\n" in content[-1]
+ assert " cmds='complete help'\n" in content
+ assert " cmds_complete='-h --help --name --shell'\n" in content
+ assert " cmds_help='-h --help'\n" in content