Kamaki commands are implemented as python classes, decorated with a special
Kamaki commands are implemented as python classes, decorated with a special
decorator called *command*. This decorator is a method of kamaki.cli that adds
decorator called *command*. This decorator is a method of *kamaki.cli* that
a new command in a CommandTree structure (kamaki.cli.commant_tree). The later
adds a new command in a *CommandTree* structure. A *CommandTree* (package
is used by interfaces to manage kamaki commands.
*kamaki.cli.commant_tree*) is a data structure used by kamaki to manage command
namespaces.
In the following, a set of kamaki commands will be implemented::
For demonstration purposes, the following set of kamaki commands will be
implemented in this document::
mygrp1 list all //show a list
mygrp1 list all //show a list
mygrp1 list details [--match=<>] //show list of details
mygrp1 list details [--match=<>] //show list of details
mygrp2 list all [regular expression] [-l] //list all subjects
mygrp2 list all [regular expression] [-l] //list all subjects
mygrp2 info <id> [name] //get information for subject with id
mygrp2 info <id> [name] //get information for subject with id
There are two command sets to implement, namely mygrp1 and mygrp2. The first
There are two command groups to implement i.e., *mygrp1* and *mygrp2*,
will contain two commands, namely list-all and list-details. The second one
containing two commands each (*list_all*, *list_details* and *list_all*, *info*
will also contain two commands, list-all and info. To avoid ambiguities,
respectively). To avoid ambiguities, command names are prefixed with the
command names should rather be prefixed with the group they belong to, e.g.
command group they belong to, e.g., *mygrp1_list_all* and *mygrp2_list_all*.
mygrp1-list-all and mygrp2-list-all.
The underscore is used to separate command namespaces.
The first command has the simplest possible syntax: no parameters, no runtime
The first command (*mygrp1_list_all*) has the simplest possible syntax: no
arguments. The second accepts an optional runtime argument with a value. The
parameters, no runtime arguments. The second accepts an optional runtime argument with a value. The third features an optional parameter and an optional
third features an optional argument and an optional runtime flag argument. The
runtime flag argument. The last is an example of a command with an obligatory
last is an example of a command with an obligatory and an optional argument.
and an optional parameter.
Samples of the expected behavior in one-command mode are following:
Examples of the expected behavior in one-command mode:
.. code-block:: console
.. code-block:: console
...
@@ -35,34 +37,32 @@ Samples of the expected behavior in one-command mode are following:
...
@@ -35,34 +37,32 @@ Samples of the expected behavior in one-command mode are following:
- - - -
- - - -
list
list
$ kamaki mygrp1 list
$ kamaki mygrp1 list
Syntax Error
Options
Options
- - - -
- - - -
all show a list
all show a list
details show a list of details
details show a list of details
$ kamaki mygrp1 list all
$ kamaki mygrp1 list all
... (mygrp1 client method is called) ...
... (a mygrp1_list_all instance runs) ...
$ kamaki mygrp2 list all 'Z[.]' -l
$ kamaki mygrp2 list all 'Z[.]' -l
... (mygrp2 client method is called) ...
... (a mygrp2_list_all instance runs) ...
$
$
The above example will be used throughout the present guide.
The CommandTree structure
The CommandTree structure
-------------------------
-------------------------
CommandTree manages a command by its path. Each command is stored in multiple
CommandTree manages a command by its namespace. Each command is stored in
nodes on the tree, so that the last term is a leaf and the route from root to
a tree path, where each node is a name. A leaf is the end term of a namespace and contains a pointer to the command class to be executed.
that leaf represents the command path. For example the commands *file upload*,
*file list* and *file info* are stored together as shown bellow::
Here is an example from the actual kamaki command structure, where the commands
*file upload*, *file list* and *file info* are represented as shown bellow::
- file
- file
''''''''|- info
''''''''|- info
|- list
|- list
|- upload
|- upload
The example used in the present, should result to the creation of two trees::
Now, let's load the showcase example on CommandTrees::
- mygrp1
- mygrp1
''''''''|- list
''''''''|- list
...
@@ -74,12 +74,12 @@ The example used in the present, should result to the creation of two trees::
...
@@ -74,12 +74,12 @@ The example used in the present, should result to the creation of two trees::
'''''''|- all
'''''''|- all
|- info
|- info
Each command group should be stored on a different CommandTree. For that
Each command group should be stored on a different CommandTree.
reason, command specification modules should contain a list of CommandTree
objects, named *_commands*
For that reason, command specification modules should contain a list of CommandTree objects, named *_commands*. This mechanism allows any interface
application to load the list of commands from the *_commands* array.
A command group information (name, description) is provided at CommandTree
The first name of the command path and a description (name, description) are needed to initializeg a CommandTree:
structure initialization:
.. code-block:: python
.. code-block:: python
...
@@ -88,15 +88,19 @@ structure initialization:
...
@@ -88,15 +88,19 @@ structure initialization:
_commands = [_mygrp1_commands, _mygrp2_commands]
_commands = [_mygrp1_commands, _mygrp2_commands]
The command decorator
The command decorator
---------------------
---------------------
The *command* decorator mines all the information necessary to build a command
All commands are specified by subclasses of *kamaki.cli.commands._command_init*
specification which is then inserted in a CommanTree instance::
These classes are called "command specifications".
The *command* decorator mines all the information needed to build a namespace
from a command specification::
class code ---> command() --> updated CommandTree structure
class code ---> command() --> updated CommandTree structure
Kamaki interfaces make use of this CommandTree structure. Optimizations are
Kamaki interfaces make use of the CommandTree structure. Optimizations are
possible by using special parameters on the command decorator method.
possible by using special parameters on the command decorator method.
.. code-block:: python
.. code-block:: python
...
@@ -108,14 +112,16 @@ possible by using special parameters on the command decorator method.
...
@@ -108,14 +112,16 @@ possible by using special parameters on the command decorator method.
:param prefix: of the commands allowed to be inserted ('' for all)
:param prefix: of the commands allowed to be inserted ('' for all)
:param descedants_depth: is the depth of the tree descedants of the
:param descedants_depth: is the depth of the tree descendants of the
prefix command.
prefix command.
"""
"""
Creating a new command specification set
Creating a new command specification set
----------------------------------------
----------------------------------------
A command specification developer should create a new module (python file) with as many classes as the command specifications to be offered. Each class should be decorated with *command*.
A command specification developer should create a new module (python file) with
one command specification class per command. Each class should be decorated
with *command*.
.. code-block:: python
.. code-block:: python
...
@@ -129,10 +135,10 @@ A command specification developer should create a new module (python file) with
...
@@ -129,10 +135,10 @@ A command specification developer should create a new module (python file) with
...
...
A list of CommandTree structures must exist in the module scope, with the name
A list of CommandTree structures must exist in the module scope, with the name
_commands, as shown above. Different CommandTree objects correspond to
*_commands*. Different CommandTree objects correspond to different command
different command groups.
groups.
Get command description
Set command description
-----------------------
-----------------------
The description of each command is the first line of the class commend. The
The description of each command is the first line of the class commend. The
...
@@ -143,25 +149,50 @@ subject with id*" description.
...
@@ -143,25 +149,50 @@ subject with id*" description.
...
...
@command(_mygrp2_commands)
@command(_mygrp2_commands)
class mygrp2_info()
class mygrp2_info():
"""get information for subject with id"""
"""get information for subject with id
Anything from this point and bellow constitutes the long description
Please, mind the indentation, pep8 is not forgiving.
"""
...
...
Description placeholders
------------------------
There is possible to create an empty command, that can act as a description
placeholder. For example, the *mygrp1_list* namespace does not correspond to an
executable command, but it can have a helpful description. In that case, create
a command specification class with a command and no code:
.. code-block:: python
@command(_mygrp1_commands)
class mygrp1_list():
"""List mygrp1 objects.
There are two versions: short and detailed
"""
.. warning:: A command specification class with no description is invalid and
will cause an error.
Declare run-time argument
Declare run-time argument
-------------------------
-------------------------
The argument mechanism allows the definition of run-time arguments. Some basic
A special argument mechanism allows the definition of run-time arguments. This
argument types are defined at the
mechanism is based on argparse and is designed to simplify argument definitions
when specifying commands.
Some basic argument types are defined at the
`argument module <code.html#module-kamaki.cli.argument>`_, but it is not
`argument module <code.html#module-kamaki.cli.argument>`_, but it is not
uncommon to extent these classes in order to achieve specialized type checking
a bad idea to extent these classes in order to achieve specialized type
and syntax control (e.g. at
checking and syntax control. Still, in most cases, the argument types of the