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.
One of the strengths of Python is that it comes with batteries included: it has a rich and versatile standard library that makes it one of the best programming languages for writing scripts for the command line.
Create a file index. js in the root of the project. This will be the main entry of the CLI tool that will initialize the commands it will have. NOTE: If you are using Windows for development, make sure that the line end character is set to LF instead of CRLF or the tool will not work.
When a Click command callback is executed, it's passed all the non-hidden parameters as keyword arguments. Notably absent is the context. However, a callback can opt into being passed to the context object by marking itself with pass_context() .
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With