Revision dc99e627

b/docs/developers/adding-commands.rst
1 1
Adding Commands
2 2
===============
3 3

  
4
Kamaki commands are implemented as python classes, decorated with a special
5
decorator called *command*. This decorator is a method of *kamaki.cli* that
6
adds a new command in a *CommandTree* structure. A *CommandTree* (package
7
*kamaki.cli.commant_tree*) is a data structure used by kamaki to manage command
8
namespaces.
4
Kamaki commands are implemented as python classes, which wear a decorator
5
called *command*. The decorator lives in *kamaki.cli* and its purpose is to
6
update the *CommandTree* structure. The *CommandTree* class (
7
*kamaki.cli.commant_tree*) manages command namespaces for kamaki.
9 8

  
10 9
For demonstration purposes, the following set of kamaki commands will be
11 10
implemented in this document::
12 11

  
13
    mygrp1 list all                         //show a list
14
    mygrp1 list details [--match=<>]        //show list of details
15
    mygrp2 list all [regular expression] [-l]       //list all subjects
16
    mygrp2 info <id> [name]      //get information for subject with id
12
    mygrp1 list all                             //show a list
13
    mygrp1 list details [--match=<>]            //show list of details
14
    mygrp2 list all [regular expression] [-l]   //list all subjects
15
    mygrp2 info <id> [--filter]                 //information on a subject
17 16

  
18
There are two command groups to implement i.e., *mygrp1* and *mygrp2*,
17
.. note:: By convention, the names of the groups describe subjects e.g.,
18
    "server", "network", "container", etc.
19

  
20
Here we get two command groups to implement i.e., *mygrp1* and *mygrp2*,
19 21
containing two commands each (*list_all*, *list_details* and *list_all*, *info*
20
respectively). To avoid ambiguities, command names are prefixed with the
21
command group they belong to, e.g., *mygrp1_list_all* and *mygrp2_list_all*.
22
The underscore is used to separate command namespaces.
22
respectively). The underscore is used to separate command namespaces and should
23
be considered as a special character in this context.
23 24

  
24 25
The first command (*mygrp1_list_all*) has the simplest possible syntax: no
25
parameters, no runtime arguments. The second accepts an optional runtime argument with a value. The third features an optional parameter and an optional
26
runtime flag argument. The last is an example of a command with an obligatory
27
and an optional parameter.
26
parameters, no runtime arguments. The second one defines one optional runtime
27
argument with a value. The third features an optional parameter and an optional
28
runtime flag argument. The last one is an example of a command with an
29
obligatory and an optional parameter.
28 30

  
29
Examples of the expected behavior in one-command mode:
31
Some examples:
30 32

  
31 33
.. code-block:: console
32 34

  
......
51 53
The CommandTree structure
52 54
-------------------------
53 55

  
54
CommandTree manages a command by its namespace. Each command is stored in
55
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.
56
CommandTree manages commands and their namespaces. Each command is stored in
57
a tree, where each node is a name. A leaf is the rightmost term of a namespace
58
and contains a pointer to the executable command class.
56 59

  
57
Here is an example from the actual kamaki command structure, where the commands
58
*file upload*, *file list* and *file info* are represented as shown bellow::
60
Here is an example from the actual kamaki command structure, featuring the
61
commands *file upload*, *file list* and *file info* ::
59 62

  
60 63
    - file
61 64
    ''''''''|- info
......
76 79

  
77 80
Each command group should be stored on a different CommandTree.
78 81

  
79
For that reason, command specification modules should contain a list of CommandTree objects, named *_commands*. This mechanism allows any interface
82
For that reason, command specification modules should contain a list of
83
CommandTree objects, named *_commands*. This mechanism allows any interface
80 84
application to load the list of commands from the *_commands* array.
81 85

  
82
The first name of the command path and a description (name, description) are needed to initializeg a CommandTree:
83

  
84 86
.. code-block:: python
85 87

  
86 88
    _mygrp1_commands = CommandTree('mygrp', 'mygrp1 description')
......
88 90

  
89 91
    _commands = [_mygrp1_commands, _mygrp2_commands]
90 92

  
93
.. note:: The name and the description, will later appear in automatically
94
    created help messages
91 95

  
92 96
The command decorator
93 97
---------------------
......
95 99
All commands are specified by subclasses of *kamaki.cli.commands._command_init*
96 100
These classes are called "command specifications".
97 101

  
98
The *command* decorator mines all the information needed to build a namespace
102
The *command* decorator mines all the information needed to build namespaces
99 103
from a command specification::
100 104

  
101 105
    class code  --->  command()  -->  updated CommandTree structure
......
141 145
Set command description
142 146
-----------------------
143 147

  
144
The description of each command is the first line of the class commend. The
145
following declaration of *mygrp2-info* command has a "*get information for
146
subject with id*" description.
148
The first line of the class commend is used as the command short description.
149
The rest is used as the detailed description.
147 150

  
148 151
.. code-block:: python
149 152

  
......
178 181
Declare run-time argument
179 182
-------------------------
180 183

  
181
A special argument mechanism allows the definition of run-time arguments. This
182
mechanism is based on argparse and is designed to simplify argument definitions
183
when specifying commands.
184
The argument mechanism is based on the standard argparse module.
184 185

  
185 186
Some basic argument types are defined at the
186 187
`argument module <code.html#module-kamaki.cli.argument>`_, but it is not
187 188
a bad idea to extent these classes in order to achieve specialized type
188
checking and syntax control. Still, in most cases, the argument types of the
189
argument package are enough for most cases.
189
checking and syntax control with respect to the semantics of each command.
190
Still, in most cases, the argument types of the argument package are enough for
191
most cases.
190 192

  
191 193
To declare a run-time argument on a specific command, the specification class
192 194
should contain a dict called *arguments* , where Argument objects are stored.
193
Each argument object is a run-time argument. Syntax checking happens at client
194
level, while the type checking is implemented in the Argument code (e.g.,
195
IntArgument checks if the value is an int).
195
Each argument object is a run-time argument. Syntax checking happens at the
196
command specification level, while the type checking is implemented in the
197
Argument subclasses.
196 198

  
197 199
.. code-block:: python
198 200

  
......
227 229
Accessing run-time arguments
228 230
----------------------------
229 231

  
230
To access run-time arguments, users can use the *_command_init* interface,
231
which implements *__item__* accessors to handle run-time argument values. In
232
other words, one may get the value of an argument with *self[<argument>]*.
232
To access run-time arguments, command classes extend the *_command_init*
233
interface, which implements *__item__* accessors to handle run-time argument
234
values. In other words, one may get the runtime value of an argument by calling
235
*self[<argument>]*.
233 236

  
234 237
.. code-block:: python
235 238

  
......
250 253
            assert self['match'] == self.arguments['match'].value
251 254
            ...
252 255

  
256
Non-positional required arguments
257
---------------------------------
258

  
259
By convention, kamaki uses positional arguments for identifiers and
260
non-positional arguments for everything else. By default, non-positional
261
arguments are optional. A non-positional argument can explicitly set to be
262
required at command specification level:
263

  
264
.. code-block:: python
265

  
266
    ...
267

  
268
    @command(_mygrp1_commands)
269
    class mygrp1_list_details(_command_init):
270
        """List of details"""
271

  
272
        arguments = dict(
273
            match=ValueArgument(
274
                'Filter output to match string', ('-m', --match'))
275
        )
276
        required = (match, )
277

  
278
A tupple means "all required", while a list notation means "at least one".
279

  
280

  
253 281
The main method and command parameters
254 282
--------------------------------------
255 283

  
......
297 325
* Runtime arguments (line 13): [-l]
298 326
* Runtime arguments help (line 13): detailed list
299 327

  
300
.. tip:: It is suggested to code the main functionality in a member method
301
    called *_run*. This allows the separation between syntax and logic. For
302
    example, an external library may need to call a command without caring
328
.. tip:: By convention, the main functionality is implemented in a member
329
    method called *_run*. This allows the separation between syntax and logic.
330
    For example, an external library may need to call a command without caring
303 331
    about its command line behavior.
304 332

  
305 333
Letting kamaki know
306 334
-------------------
307 335

  
308
Kamaki will load a command specification *only* if it is set as a configurable
309
option. To demonstrate this, let the command specifications coded above be
310
stored in a file named *grps.py*.
336
Assume that the command specifications presented so far be stored in a file
337
named *grps.py*.
311 338

  
312 339
The developer should move the file *grps.py* to *kamaki/cli/commands*, the
313 340
default place for command specifications

Also available in: Unified diff