Tutorial

The tutorial assumes that the example snippets are saved as main.py.

Expose single function

$ python3 main.py hello
hello
"Expose single function"

import argparse
import argparse_action


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    argparse_action.add_action(parser, echo)
    namespace = parser.parse_args()
    namespace.action(namespace)


def echo(word):
    print(word)


if __name__ == "__main__":
    main()
$ python3 main.py -h
usage: main.py [-h] word

Expose single function

positional arguments:
  word

options:
  -h, --help  show this help message and exit

Expose multiple functions as commands

$ python3 main.py echo hello
hello
"Expose multiple functions as commands"
import sys
import argparse
import argparse_action

def main():
    namespace = parser.parse_args()
    namespace.action(namespace)

parser = argparse.ArgumentParser(description=__doc__)
action = argparse_action.Action(parser)

@action.add()
def echo(parameter):
    "echo the cli argument"
    print(parameter)

@action.add()
def oche(parameter):
    "echo the revered cli argument"
    acc = list(parameter)
    acc.reverse()
    print("".join(acc))

if __name__ == "__main__":
    main()
$ python3 main.py  -h
usage: main.py [-h] command ...

Expose multiple functions as commands

positional arguments:
  command
    echo      echo the cli argument
    oche      echo the revered cli argument

options:
  -h, --help  show this help message and exit
$ python3 main.py oche hello
olleh

Arbitrary argument is handled as nargs=* argument

$ python3 main.py spam egg
"Arbitrary argument is handled as nargs=* argument"
import sys
import argparse
import argparse_action

def main():
    namespace = parser.parse_args()
    namespace.action(namespace)

parser = argparse.ArgumentParser(description=__doc__)
action = argparse_action.Action(parser)

@action.add()
def spam(word, *spams):
   for spam in spams:
       print(word + spam)

if __name__ == "__main__":
    main()
$ python3 main.py spam -h
usage: main.py spam [-h] word [spams ...]

positional arguments:
  word
  spams

options:
  -h, --help  show this help message and exit
$ python3 main.py spam egg. spam spam-spam
egg.spam
egg.spam-spam

Short option can be defined with single character function argument

$ python3 main.py echo -u hello
HELLO
"Short option can be defined with single character function argument"
import sys
import argparse
import argparse_action

def main():
    namespace = parser.parse_args()
    namespace.action(namespace)

parser = argparse.ArgumentParser(description=__doc__)
action = argparse_action.Action(parser)

@action.add()
def echo(word, u=False):
    print(word.upper() if u else word)

if __name__ == "__main__":
    main()

Extra argpasre options can be injected

$ python3 main.py repeat spam -nn
spamspam
"Extra argpasre options can be injected"
import sys
import argparse
import argparse_action

def main():
    namespace = parser.parse_args()
    namespace.action(namespace)

parser = argparse.ArgumentParser(description=__doc__)
action = argparse_action.Action(parser)

@action.add(n={"action": "count"})
def repeat(word, n=0):
    "repeat the word"
    print(word * n)

if __name__ == "__main__":
    main()
$ python3 main.py repeat -h
usage: main.py repeat [-h] [-n] word

positional arguments:
  word

options:
  -h, --help  show this help message and exit
  -n          default: 0

Argparse ‘append’ action can be forced with sequence default value

$ python3 main.py log --level debug --level info MY_MESSAGE
Level.debug: MY_MESSAGE
Level.info: MY_MESSAGE
"Argparse 'append' action can be forced with sequence default value"
import sys
import enum
import collections.abc
import argparse
import argparse_action

def main():
    namespace = parser.parse_args()
    namespace.action(namespace)

parser = argparse.ArgumentParser(description=__doc__)
action = argparse_action.Action(parser)

class Level(enum.Enum):
    debug = enum.auto()
    info = enum.auto()

@action.add()
def log(message, level: collections.abc.Sequence[Level]=()):
    for l in level:
        print(f"{l}: {message}")

if __name__ == "__main__":
    main()

Initiate python logging with argparse_action

$ python3 main.py --log-format '%(levelname)s:%(message)s' --log-level debug emit-debug my-message
STDERR:
'DEBUG:my-message'
"Initiate python logging with argparse_action"
import argparse
import argparse_action
import logging

parser = argparse.ArgumentParser(description=__doc__)
action = argparse_action.Action(parser)

def main():
    argparse_action.add_log_arguments(parser)
    args = parser.parse_args()
    argparse_action.init_logging(args)
    return args.action(args)

@action.add()
def emit_debug(message):
    logging.debug(message)

if __name__ == "__main__":
    exit(main())
$ python3 main.py -h
usage: main.py [-h] [--log-level {debug,warning,info,error,fatal,critical}]
               [--log-format LOG_FORMAT] [--log-datefmt LOG_DATEFMT]
               [--log-syslog FACILITY | --log-none | --log-file LOG_FILE | --log-console]
               command ...

Initiate python logging with argparse_action

positional arguments:
  command
    emit-debug

options:
  -h, --help            show this help message and exit
  --log-level {debug,warning,info,error,fatal,critical}
                        default is 'info'
  --log-format LOG_FORMAT
                        default is '%(asctime)s %(name)s %(levelname)s
                        %(message)s'
  --log-datefmt LOG_DATEFMT
                        default is '%Y-%m-%d %H:%M:%S'
  --log-syslog FACILITY
                        Log into syslog
  --log-none            Disable logging
  --log-file LOG_FILE   Log into LOG_FILE
  --log-console         Log into console
$ python3 main.py emit-debug my-message

Arbitrary argument can be annoted

$ python3 main.py summa 2 3
5
"Arbitrary argument can be annoted"
import sys
import argparse
import argparse_action

def main():
    namespace = parser.parse_args()
    namespace.action(namespace)

parser = argparse.ArgumentParser(description=__doc__)
action = argparse_action.Action(parser)

@action.add()
def summa(*num: int):
    print(sum(num))

if __name__ == "__main__":
    main()

Register command alias

$ python3 main.py echo hello
hello
$ python3 main.py print bello
bello
"Register command alias"
import sys
import argparse
import argparse_action

def main():
    namespace = parser.parse_args()
    namespace.action(namespace)

parser = argparse.ArgumentParser(description=__doc__)
action = argparse_action.Action(parser)

@action.add("print", "p")
def echo(parameter):
    "echo the cli argument"
    print(parameter)

if __name__ == "__main__":
    main()
$ python3 main.py p hello-bello
hello-bello

Default log handler can be defined

$ python3 main.py emit-debug my-message
"Default log handler can be defined"
import argparse
import argparse_action
import logging

parser = argparse.ArgumentParser(description=__doc__)
action = argparse_action.Action(parser)

def main():
    argparse_action.add_log_arguments(parser)
    args = parser.parse_args()
    argparse_action.init_logging(
        args, default_handler=argparse_action.create_syslog_handler()
    )
    return args.action(args)

@action.add()
def emit_debug(message):
    logging.debug(message)

if __name__ == "__main__":
    exit(main())

Enum annotation register argument choices

$ python3 main.py log message --level error
E: message
"Enum annotation register argument choices"
import sys
import enum
import argparse
import argparse_action

def main():
    namespace = parser.parse_args()
    namespace.action(namespace)

parser = argparse.ArgumentParser(description=__doc__)
action = argparse_action.Action(parser)

class Level(enum.Enum):
    debug = enum.auto()
    info = enum.auto()
    error = enum.auto()

@action.add()
def log(word, level: Level=Level.info):
    if level == Level.debug:
        print(f"D: {word}")

    elif level == Level.info:
        print(f"I: {word}")

    elif level == Level.error:
        print(f"E: {word}")

    else:
        print(word)

if __name__ == "__main__":
    main()
$ python3 main.py log -h
usage: main.py log [-h] [--level {debug,info,error}] word

positional arguments:
  word

options:
  -h, --help            show this help message and exit
  --level {debug,info,error}
                        default: info
$ python3 main.py log message
I: message

CLI option from default value

$ python3 main.py echo hello
hello joe
"CLI option from default value"
import sys
import argparse
import argparse_action

def main():
    namespace = parser.parse_args()
    namespace.action(namespace)

parser = argparse.ArgumentParser(description=__doc__)
action = argparse_action.Action(parser)

@action.add()
def echo(word, name="joe"):
    print(f"{word} {name}")

if __name__ == "__main__":
    main()
$ python3 main.py echo hello --name sam
hello sam
$ python3 main.py echo -h
usage: main.py echo [-h] [--name NAME] word

positional arguments:
  word

options:
  -h, --help   show this help message and exit
  --name NAME  default: joe

CLI option flag from boolean default value

$ python3 main.py echo hello
hello
"CLI option flag from boolean default value"
import sys
import argparse
import argparse_action

def main():
    namespace = parser.parse_args()
    namespace.action(namespace)

parser = argparse.ArgumentParser(description=__doc__)
action = argparse_action.Action(parser)

@action.add()
def echo(word, upper=False):
   print(word.upper() if upper else word)

if __name__ == "__main__":
    main()

$ python3 main.py echo hello --upper
HELLO