Tutorial

Welcome to the tutorial for Commandeer. In this tutorial you will learn to make more and more complex commands that can be exposed on the command line, until you have finally used all available features. You can go to the example containing everything right now, if you want.

All of the examples shown in here are available from the samples/ folder in the commandeer sources.

First steps: command functions

The first thing you need to know is that you don’t really need to do much to expose your program’s functions on the command line. There are only two things you need to do:
  • name each function that you want to make available as a command with the ending _command.
  • add a call to commandeer.cli() to your program.

In the simplest case, your program would look like program1.py:


import commandeer

def my_func_command():
  	print("this is my function")

if __name__ == '__main__':
    commandeer.cli()

That’s all there is to it! Ok, we added the magic line if __name__ == '__main__': but that was just to make our program importable.

What this simply program will do for you now is to give you a command line that looks like this:

$ python program1.py
  Usage: program1.py command [options]

  Here are the commands you can try:

    help         Show this help screen.
    my_func

  If you need help on any of them, try "program1.py help command" for any of them.  $ python program1.py
$ python program1.py my_func
this is my function

Awesome! Simple command line without doing anything special!

Documentation for your commands

But the help doesn’t look nice yet! The help you see when you start your program without any commands is generated from the docstrings in your program, so let’s add a few of them in program2.py

"""Show the different uses of Commandeer"""

import commandeer

def info_command():
	"""Print some program information
	
	At the moment, this is pretty empty, but we will expand upon that in the future!
	"""
	print("this is my function")

if __name__ == '__main__':
	commandeer.cli()

This make the help screen a lot nicer, and we even get help for each command:

$ python program2.py
  Show the different uses of Commandeer
  Usage: program2.py command [options]

  Here are the commands you can try:

    help      Show this help screen.
    info      Print some program information

  If you need help on any of them, try "program2.py help command" for any of them.
$ python program2.py help info
Usage: program2.py info
  Print some program information

  At the moment, this is pretty empty, but we will expand upon that in the future!

Now, let’s add a few parameters!

Optional parameters

Any parameters that have defaults in your functions will be automatically mapped to command line switches, as in program3.py

"""Show the different uses of Commandeer"""

import commandeer

def info_command(extrainfo=False, showdate=True, name='myself', age=30):
	"""Print some program information
	
	At the moment, this is pretty empty, but we will expand upon that in the future!
	"""
	print("This is my advanced info function")
	if extrainfo:
		print("Extra info was requested. The extra info is:")
		print("I am talking to {}, who is {} years old". format(name, age))
	if showdate:
		from datetime import datetime
		print(datetime.now())

if __name__ == '__main__':
	commandeer.cli()

Let’s try it out:

$ python program3.py info
This is my advanced info function
$ python program3.py info --extrainfo
This is my advanced info function
Extra info was requested. The extra info is:
I am talking to myself, who is 30 years old
$ python program3.py info --showdate --extrainfo --age=45 --name John
This is my advanced info function
Extra info was requested. The extra info is:
I am talking to John, who is 45 years old
2012-09-05 13:27:27.047092

Note that each of the parameters gets their default value if it’s not specified on the command line. Also, all parameters are typed, so if your default is a number, you’ll get a number, too – if it can be parsed. If it can’t, you’ll get the string that was given on the command line.

Warning

Remember: don’t trust the input you get! Malicious users will try to pass stuff that breaks your program or makes it misbehave. Therefore: always sanitize your input before using it!

Note also that the switch format is pretty flexible. It doesn’t care about the number of dashes, whether you use a = to separate switch and value or a space or the order of the switches.

For switches that have a boolean default value, you also get an extra command line switch that starts with a no. In our example you could have used:

$ python program3.py info --noshowdate

which would be the same as:

$ python program3.py info --showdate=False

Parameter documentation

Commandeer will automatically generate some help information for the parameters you specified:

$ python program3.py help info
Usage: program3.py info  [optional switches]
  Print some program information

  At the moment, this is pretty empty, but we will expand upon that in the future!

  Command line options:
    --age
                 default value: 30
    --extrainfo
                 default value: False
    --name
                 default value: myself
    --showdate
                 default value: True

This is nice, but not really that helpful, because we still don’t know what these parameters mean. To help with this, you can add documentation for your parameters to your docstring using doxygen or epydoc syntax, with the \param directive or the @param directive. There’s no difference between the two ways and you can mix them if you wish. Here’s how it looks in program4.py:

"""Show the different uses of Commandeer"""

import commandeer

def info_command(extrainfo=False, showdate=True, name='myself', age=30):
	"""Print some program information
	
	At the moment, this is pretty empty, but we will expand upon that in the future!
	@param extrainfo Enable extra information.
	@param name The name we inform about, part of the extra information.
	@param age The age of the person we inform about, part of the extra information.
	\param showdate Show a timestamp at the bottom of the ouput.
	"""
	print("This is my advanced info function")
	if extrainfo:
		print("Extra info was requested. The extra info is:")
		print("I am talking to {}, who is {} years old". format(name, age))
	if showdate:
		from datetime import datetime
		print(datetime.now())

if __name__ == '__main__':
	commandeer.cli()

And here’s how the help looks now:

$ python program4.py help info
Usage: program4.py info  [optional switches]
  Print some program information

  At the moment, this is pretty empty, but we will expand upon that in the future!

  Command line options:
    --age        The age of the person we inform about, part of the extra information.
                 default value: 30
    --extrainfo  Enable extra information.
                 default value: False
    --name       The name we inform about, part of the extra information.
                 default value: myself
    --showdate   Show a timestamp at the bottom of the ouput.
                 default value: True

Required parameters

After the optional command line switches, of course there’s the option to add required parameters. These are, as in Python, positional arguments to your command function. There’s not much else to it, so here’s how it looks like:

"""Show the different uses of Commandeer"""

import commandeer

def info_command(type, feeling, extrainfo=False, showdate=True, name='myself', age=30):
	"""Print some program information
	
	At the moment, this is pretty empty, but we will expand upon that in the future!
	@param type The type of function that this is.
	@param feeling The feeling the function has.
	@param extrainfo Enable extra information.
	@param name The name we inform about, part of the extra information.
	@param age The age of the person we inform about, part of the extra information.
	\param showdate Show a timestamp at the bottom of the ouput.
	"""
	print("This is my {} info function, it is feeling {}".format(type, feeling))
	if extrainfo:
		print("Extra info was requested. The extra info is:")
		print("I am talking to {}, who is {} years old". format(name, age))
	if showdate:
		from datetime import datetime
		print(datetime.now())

if __name__ == '__main__':
	commandeer.cli()

The help and error messages will be automatically generated here, too, so we end up with:

$ python program5.py help info
Usage: program5.py info type feeling [optional switches]
  Print some program information

  At the moment, this is pretty empty, but we will expand upon that in the future!

  Required arguments:
    type     The type of function that this is.
    feeling  The feeling the function has.

  Command line options:
    --age        The age of the person we inform about, part of the extra information.
                 default value: 30
    --extrainfo  Enable extra information.
                 default value: False
    --name       The name we inform about, part of the extra information.
                 default value: myself
    --showdate   Show a timestamp at the bottom of the ouput.
                 default value: True

$ python program5.py info
Error: missing required arguments
    type     The type of function that this is.
    feeling  The feeling the function has.
Try 'help info' for a full documentation of this command.
$ python program5.py info great
Error: missing required arguments
    type     'great'
    feeling  The feeling the function has.
Try 'help info' for a full documentation of this command.
$ python program5.py info great beautiful
This is my great info function, it is feeling beautiful
2012-09-05 21:41:18.301483

It doesn’t matter in which order the user passes these arguments to your program – as long as they are clearly recognizable. Each switch scans the command line for arguments and will accept any string that’s written directly after it. For example, this won’t work:

$ python program5.py info --showdate type feeling
Error: missing required arguments. Here is a list of arguments this command requires and the values you gave for them:
    type     'feeling'
    feeling  The feeling the function has.
Try 'help info' for a full documentation of this command.

A flexible number of arguments

Sometimes you will want to accept an unknown number of extra arguments, like file names or additional help specifiers. You can do so by using a vararg. Varargs will automatically receive all extra arguments if there are any. If there are no arguments, they will stay empty. Have a look at program6.py for an example:

"""Show the different uses of Commandeer"""

import commandeer

def echo_command(*inp):
	"""Print all the words that were passed on the command line
	
	This is just a simple echo command.
	"""
	print(' '.join(inp))

if __name__ == '__main__':
	commandeer.cli()

Here’s how it would look like on the command line:

$ python program6.py help echo
Usage: program6.py echo [optional arguments]
  Print all the words that were passed on the command line

  This is just a simple echo command.
$ python program6.py echo hello world
hello world
$ python program6.py echo *
program1.py program2.py program3.py program4.py program5.py program6.py

Note in the help the additional [optional arguments].

Aliases

And finally, you can add as many aliases as you want to your commands. These aliases will work in any place where the command name works, too. To attach one or more aliases to a command, simply add them to the function object.

This is illustrated in program7.py:

"""Show the different uses of Commandeer"""

import commandeer

def echo_command(*inp):
	"""Print all the words that were passed on the command line
	
	This is just a simple echo command.
	"""
	print(' '.join(inp))
echo_command.aliases = 'redisplay', 'parrot', 'reply', 'reproduce'



if __name__ == '__main__':
	commandeer.cli()

Now we can use any of redisplay, parrot, reply or reproduce in place of echo.

$ python program7.py echo hello world
hello world
$ python program7.py parrot hello world
hello world
$ python program7.py redisplay hello world
hello world
$ python program7.py help parrot
Usage: program7.py parrot [optional arguments]
  Print all the words that were passed on the command line

  This is just a simple echo command.

You can use this to add names to commands that would not be available as function names in python, like the ? that is mapped to the help command by default:

$ python program7.py ? parrot
Usage: program7.py parrot [optional arguments]
  Print all the words that were passed on the command line

  This is just a simple echo command.

However, you need to make sure that aliases are

A full example!

So, finally, here is a full example that shows all features. For a description of these features, you can read the tutorial (again) or go the the feature overview. The following script is also included with the Commandeer source code, inside file called samples/full.py.

"""This is a sample script that shows two commands and how to call them from Commandeer."""

import commandeer
import datetime

def func_command(argument1, argument2):
	"""A functional command: adding
	
	This command works by simply outputting its parameter."""
	try:
		a = float(argument1)
		b = float(argument2)
	except ValueError:
		print("Could not convert arguments to numbers. Please make sure they are in the right format!")
		return
	print(a+b)
func_command.aliases = 'add', 	
	
def log_command(logcode, *input, timestamp=True, indent=0):
	"""Outputs the input, with an optional timestamp and some indenting.
	
	All of the input arguments are simply output on the standard out. If you specify indenting,
	the output will be prepended by that number of spaces. If you set timestamp to True, the
	output will be prepended by '[timestamp] ' for fun.
	@param logcode The topic or code that this log will be added to.
	\param timestamp Add a timestamp to the output. A real timestamp.
	\param indent The number of spaces the output should be indented by.
	"""
	echo_str = "[{}] {}".format(logcode, ' '.join(input))
	if timestamp:
		echo_str = "[{}] {}".format(str(datetime.datetime.now()), echo_str)
	echo_str = " " * indent + echo_str
	print(echo_str)
	
if __name__ == '__main__':
	commandeer.cli()

To find out what it does, try some of the following:

$ python sample.py help
  This is a sample script that shows two commands and how to call them from Commandeer.
  Usage: sample.py command [options]

  Here are the commands you can try:

    func      A functional command: adding
    help      Show this help screen.
    log       Outputs the input, with an optional timestamp and some indenting.

  If you need help on any of them, try "sample.py help command" for any of them.
$ python sample.py help log
Usage: sample.py log logcode [optional arguments] [optional switches]
  Outputs the input, with an optional timestamp and some indenting.

  All of the input arguments are simply output on the standard out. If you specify indenting, the output will be prepended by that number of spaces. If you set timestamp to True, the output will be prepended by '[timestamp] ' for fun.

  Required arguments:
    logcode  The topic or code that this log will be added to.

  Command line options:
    --timestamp  Add a timestamp to the output. A real timestamp.
                 default value: True
    --indent     The number of spaces the output should be indented by.
                 default value: 0

$ python sample.py help func
Usage: sample.py func argument1 argument2
  Aliases: add

  A functional command: adding

  This command works by simply outputting its parameter.

  Required arguments:
    argument1
    argument2
$ python sample.py func 2 3
5.0
$ python sample.py add 2.3 abc
Could not convert arguments to numbers. Please make sure they are in the right format!
$ python sample.py log warning this is not an argument
[2012-09-06 00:29:05.489442] [warning] this is not an argument