views:

52

answers:

1

Hi

I'm trying to do a CLI, preferrably written in Python. I need a multi-level CLI, and I want tab completion.

I looked at the cmd module (from the Python standard library) and readline with the "complete" function (for tab completion).

They both lacked at something, i.e. I haven't figured out how to handle multiple levels such as:

level1
level2
    level2_subcommand_1
    level2_subcommand_2
level3
    level3_subcommand_1

Example: If I typed:

cmd> level2

, I want to see level2_subcommand_1 and level2_subcommand_2 appearing when I hit the tab key, but no level1 and no level3.

I was unable to do so with the cmd lib as well as with readline.

+3  A: 

It works perfectly fine for me with the cmd module in Python 2.6.5. Here is the sample code I was using to test this:

import cmd

class MyInterpreter(cmd.Cmd):
    def do_level1(self, args):
        pass

    def do_level2_subcommand_1(self, args):
        pass

    def do_level2_subcommand_2(self, args):
        pass

    def do_level3_subcommand_1(self, args):
        pass

MyInterpreter().cmdloop()

When I type "level2" on the command line and then press Tab, the line gets expanded to level2_subcommand_ as this is the common prefix to all the completion proposals. When I press Tab again without typing anything, the next line correctly shows level2_subcommand_1 and level2_subcommand_2. Is this what you are looking for?

Another variant for the case of sub-commands is to create a sub-interpreter for them:

class SubInterpreter(cmd.Cmd):
    prompt = "(level2) "

    def do_subcommand_1(self, args):
        pass

    def do_subcommand_2(self, args):
        pass

    def do_quit(self, args):
        return True
    do_EOF = do_quit

class MyInterpreter(cmd.Cmd):
    def do_level1(self, args):
        pass

    def do_level2(self, args):
        sub_cmd = SubInterpreter()
        sub_cmd.cmdloop()

    def do_level3(self, args):
        pass

The above variant gives you level1, level2 and level3 in your "main" interpreter. When you invoke level2 in your main interpreter, it constructs the sub-interpreter and calls its command loops. The sub-interpreter has a different prompt from the main interpreter, so you can always tell which interpreter you are in. The sub-interpreter then gives you subcommand_1, subcommand_2, subcommand_3 and quit. quit takes you back to the main interpreter, and so does the EOF character.

Tamás
Hi, thanks for your answer. The second example looks like it could do what I want. I have modified it (it calls SubInterpreter instead of SubInterpreterForLevel2) but it doesn't work. It's like I'm stuck at the first level (MyInterpreter).
daniel meier
Okay, I tested my second example in an actual Python interpreter. Looks like `SubInterpreterForLevel2` should be called `SubInterpreter` (as you correctly noted), plus the `do_quit` function was missing the `args` argument, but otherwise it works perfectly fine for me. Typing `level2` changes the prompt to `(level2)` and takes me to the sub-interpreter. Typing `quit` in `(level2)` takes me back to `(Cmd)`. Are you getting any error message when you type `level2`?
Tamás