Link Search Menu Expand Document

Command line arguments

Table of contents

  1. parseopt (standard library)
  2. docopt
  3. cligen

The standard library provides a basic library called parseopt to parse command line strings. There are several alternatives (easily installed via nimble), and here I’ll show two that can be interesting:

  • cligen, that converts your procedure’s expected parameters in the program’s documentation (useful for quick prototyping).
  • docopt, that allows you to write the documentation and will parse it to retreive the command line parameters you need (available also for Python and other programming languages, see http://docopt.org/).

parseopt (standard library)

The standard library provides a very basic options parser: parseopt. It’s quite a basic library, so I’ll just place an example here. I personally consider the user interface (the command line interface, in this case) to be a critical aspect of your programs, so I would recommend using more sophisticated libraries, but being installed by default it’s worth knowing that it exists.

The main limitation of parseopt is that it only supports the --key=value syntax and not the --key valueone.

import parseopt
import os
from strutils import parseint

# Prints version
proc writeVersion() =
  echo getAppFilename().extractFilename(), "0.1.0"

# Print help and exit
proc writeHelp() =
  writeVersion()
  echo """

  -h, --help        : show help
  -v, --version     : show version
  -m, --message STR : Message
  -t, --times INT   : Repeat message INT times
  """
  quit()

proc cli() =
  # Directly accessing the app name and parameters
  echo "# Program name: ", getAppFilename().extractFilename()
  echo "# Number of Parameters: ", paramCount()

  # Print all the parameters by index
  for paramIndex in 1 .. paramCount():    
    echo "# Raw param: ", paramIndex, ": ", paramStr(paramIndex)

  echo "---"

  var
    argCtr : int
    message: string
    times = 1
    i = 0

  # Loop trough all arguments
  for kind, key, value in getOpt():
    case kind

    # Positional arguments
    of cmdArgument:
      echo "# Positional argument ", argCtr, ": \"", key, "\""
      argCtr.inc

    # Switches
    of cmdLongOption, cmdShortOption:
      case key
      of "v", "version":
        writeVersion()
        quit()
      of "h", "help":
        writeHelp()
      of "m", "message":
        message = value
      of "t", "times":
        times = parseInt(value)
      else:
        echo "Unknown option: ", key

    of cmdEnd:
      discard

  if len(message) == 0:
    echo "No message specified :("

  while i < times:
    echo message
    i += 1

when isMainModule:
  cli()

docopt

If you never used a docopt inspired library (yes, there’s a Python docopt too), I recommend you have a look at their brilliant introductory video first. The documentation is available at their GitHub repository and of course you first need to install the library with nimble install docopt being a non standard library.

Reading the documentation is the best way to have a look at all the features, and here I report a simple example:

import  docopt
const doc = """
CoolSeq - a program to do things

Usage:
  args_docopt status
  args_docopt list
  args_docopt analyse <directory> <database> [-o|--output=<outputFile>]

Options:
  status                      Check API Status
  list                        Check Result List
  convert                     Upload Images, convert to PDF and download result.pdf
  <directory>                 Specify directory with input files
  <database>                  Reference database
  -o, --output=<outputFile>   Output filename [default: result.bam]
"""

proc main() =
  # This is needed to parse the docstring into the "args" object
  let args = docopt(doc, version = "1.0")

  if args["status"]:
    echo "So you want to know the status! OK!"
  if args["list"]:
    echo "This is the list... finished!"
  if args["analyse"]:
    echo "CONVERTING:"
    echo "Directory: ", $args["<directory>"]
    echo "Reference: ", $args["<database>"]
    echo "Output:    ", $args["--output"] # note the default!

when isMainModule:
  main()

cligen

While docopt let you write the documentation and will take care of parsing the command line arguments accordingly, cligen does the opposite: you code the required parameters and will dispatch the documentation for the user. It will automatically include a --help switch for you, and unlike parseopt will also recognize --db name (without the equal sign). Also cligen requires installation via nimble install cligen.

import strutils, os

proc compareQueryWithDb(query, db: string, kmer = 8, complement = false) =
  let progName = split(getAppFilename(), "/")[getAppFileName().count("/")]

  if query != "" and db != "":
    echo "Query: ", query
    echo "Database: ", db
    echo "K-mer size: ", kmer
    echo "Complement: ", complement
  else:
    echo "ERROR\n", progName, " needs query and target filenames..."

when isMainModule: import cligen;dispatch(compareQueryWithDb)