Input

To reduce clutter, it is recommended to put the YAML data in a top-level string variable _cligen_data in your __init__.py file. If you invoke cligen gen, or just cligen (as gen is the default subcommand), it will try to find _cligen_data in __init__.py and to open a file cli.yaml, both in the current directory.

Exactly one of the two has to be available, but you can have cli.yaml and an __init__.py without a _cligen_data variable. Alternatively you can specify an explicit file using e.g. cligen --input .cligen.yaml. In that case neither __init_.py nor cli.yaml are tried. If the argument to --input ends in .py the file needs to contain a variable _cligen_data, all other files are loaded as YAML.

A complete _cligen_data "section" would look like:

_cligen_data = """\
!Cli 0:
- !Instance driving.Direction
- !Option [verbose, v, !Help increase verbosity level, !Action count]
- left:
  - !Help turning to the left
  - !Option [u-turn, U, !Type bool, !Help make a U-turn]
- right:
  - !H turning to the right
"""

In the rest of this documentation most often only the YAML part will be shown in examples, leaving out the first and last line.

YAML format

At the root of the YAML document is a mapping with as key the scalar 0 with tag !Cli (if the tag would be on a line of its own, it would apply to the mapping that includes the key 0). The 0 indicates the first (and currently only) format for the value for that key. If there is a second version in the future, the YAML document can contain both versions and some way to select the non-default version will be provided as an option to cligen.

There are other root level keys, but they are currently only used when writing tests for cligen.

The value for !Cli 0 is a sequence. The sequence elements are either tagged node (scalar/sequence/mapping) or untagged mappings.

If an element is an untagged mapping, it should have a single key-value pair and the key is the name of a subcommand and the value is again a sequence of either tagged nodes and/or untagged mappings. Thus allowing for subcommands of subcommands. All subcommand name for one parent need to be unique, although this is not enforced at the YAML parser level, as the keys are not part of one mapping. The root level is not required to have subcommand.

Some tags (e.g. !Instance) may only appear at the root level. Other tags (e.g. !Option) can appear for both root level and subcommand, or also within a tagged non-scalar node (e.g. !Help).

Why ! tagged nodes

Deciding on a syntax for configuration specifications in YAML gives you more options, than e.g. in JSON and other formats. In JSON you would have to interpret object keys to determine what to do with a value, you can do that in YAML as well to get something like:

cli 0:
- instance: driving.Direction
- option: [verbose, v, help: increase verbosity level, action: count]
- left:
  - help: turning to the left
  - option: [u-turn, U, type: bool, help: make a U-turn]
- right:
  - h: turning to the right

apart from personal preference for a syntax, often based on what one is used to, this would force a different way of specifying subcommands, as e.g. otherwise you could not have a subcommand instance or any of the other keys that are actually tags for their values.

So you would have to use something like:

- subcommand:
  - name: left
  - help: ...
  - option: [ ... ]
- subcommand:
  - name: right

which arguable doesn't make things more readable. And for tagged literal block style scalar text at the root of a document, in a multi-document YAML stream (as used in the source for the documentation you are now reading), such a transform would force an unnatural indentation of those text.

Tags without a value

In YAML block style collections, you can specify a tag without a following value:

- left:
  - !DefaultSubCommand
  - !Help turning to the left

The tagged value is actually None, as if you had specified !DefaultSubComamnd null or !DefaultSubCommand ~.

The examples use flow style only there were no tags without a value can be inserted (options, arguments, subcommands with aliases), but there is nothing keeping you from providing a larger part of the whole specification in flow style YAML, in which case you should make the null value for such tags explicit.