Application

Application with bindings for commands

The application object handles all the initial configuration to set up the run-time environment.

Quick demo:

>>> from pyapp.app import CliApplication

>>> app = CliApplication()

>>> @app.command()
>>> def hello(*, verbose: bool):
...     if verbose:
...         print("Being verbose!")
...     print("Hello")

>>> if __name__ == '__main__':
...     app.dispatch()

This example provides an application with a command hello that takes an optional verbose flag. The framework also provides help, configures and loads settings (using pyapp.conf), an interface to the checks framework and configures the Python logging framework.

There are however a few more things that are required to get this going. The CliApplication class expects a certain structure of your application to allow for it’s (customisable) defaults to be applied.

Your application can have one of two structures

An application:

my_app/__init__.py          # Include a __version__ variable
       __main__.py          # This is where the quick demo is located
       default_settings.py  # The default settings file
       checks.py            # Optional checks file

A single script:

my_app.py                   # A script that contains the `CliApplication`

Generation of CLI from command Signature

New in version 4.4.

As of pyApp 4.4 command functions can supply all required arguments in the function signature.

As an example consider the command function:

@app.command
def my_command(
    arg1: str,
    *,
    arg2: bool= Arg(help="Enable the argilizer"),
    arg3: int = 42,
    arg4: str = Arg("-a", choices=("foo", "bar"), default="foo")
):
    ...

This translates into the following on the CLI:

> python -m my_app my_command --help
usage: my_app my_command [-h] ARG1 [--arg2] [--arg3 ARG3]
                         [--arg4 {foo,bar}]

positional arguments:
  ARG1

optional arguments:
  -h, --help  show this help message and exit
  --arg2    Enable the argilizer
  --arg3
  --arg4 {foo,bar}

The following types are supported as arguments:

  • Basic types eg int, str, float, this covers any type that can be provided to argparse in the type field.

  • bool, this is made into an argparse store_true action.

  • Enum types using the pyApp EnumAction.

  • Generic types
    • Mapping/Dict as well as a basic dict for Key/Value pairs

    • Sequence/List for typed sequences, nargs="+" for positional arguments of action="append" for optional.

    • Tuple for typed sequences of a fixed size eg nargs=len(tuple). Only the first type is used, the others are ignored.

  • FileType from argparse.

Tip

Too get access to the parse results from argparse provide a vairable with the type pyapp.app.CommandOptions.

CliApplication

class pyapp.app.CliApplication(root_module=None, *, prog: str = None, description: str = None, epilog: str = None, version: str = None, ext_white_list: Sequence[str] = None, ext_allow_list: Sequence[str] = None, ext_block_list: Sequence[str] = None, application_settings: str = None, application_checks: str = None, env_settings_key: str = None, env_loglevel_key: str = None)[source]

Application interface that provides a CLI interface.

Parameters:
  • root_module – The root module for this application (used for discovery of other modules)

  • prog – Name of your application; defaults to sys.argv[0]

  • description – A description of your application for –help.

  • version – Specify a specific version; defaults to getattr(root_module, ‘__version__’)

  • ext_allow_list – Sequence of extension names or globs that are allowed; default is None or all extensions.

  • ext_block_list – Sequence of extension names or globs that are blocked; default is None or no blocking.

  • application_settings – The default settings for this application; defaults to root_module.default_settings

  • application_checks – Location of application checks file; defaults to root_module.checks if it exists.

  • env_settings_key – Key used to define settings file in environment.

  • env_loglevel_key – Key used to define log level in environment

command(handler: Callable[[...], int | None] | Callable[[Namespace], int | None] | Callable[[...], Awaitable[int | None]] | Callable[[Namespace], Awaitable[int | None]] = None, *, name: str = None, aliases: Sequence[str] = (), help_text: str = None, loglevel: int = 20) CommandProxy

Decorator for registering handlers.

Parameters:
  • handler – Handler function

  • name – Optional name to use for CLI; defaults to the function name.

  • aliases – A sequence a name aliases for this command.

  • help_text – Information provided to the user if help is invoked; default is taken from the handlers doc string.

  • loglevel – The default log-level when using this command.

Changed in version 4.3: Async handlers supported.

Changed in version 4.15: Add loglevel option to allow per-command log levels to be set.

create_command_group(name: str, *, aliases: Sequence[str] = (), help_text: str = None) CommandGroup

Create a command group.

Parameters:
  • name – Name of the command group

  • aliases – A sequence a name aliases for this command group.

  • help_text – Information provided to the user if help is invoked.

default(handler: Callable[[...], int | None] | Callable[[Namespace], int | None] | Callable[[...], Awaitable[int | None]] | Callable[[Namespace], Awaitable[int | None]])

Decorator for registering a default handler.

Changed in version 4.3: Async handlers supported.

dispatch(args: Sequence[str] = None) None[source]

Dispatch command to registered handler.

Events

CliApplication generates the following events, all methods are provided with the argparse namespace.

pre_dispatch[[argparse.Namespace], None]

Generated before command dispatch is called

post_dispatch[[Optional[int], argparse.Namespace], None]

Generated after command dispatch returns without error includes the return code if one is provided.

dispatch_error[[Exception, argparse.Namespace], None]

Generated when an exception is raised in a command function before the standard exception reporting.

Arguments

Any command associated with a pyApp application can be expanded with arguments. Arguments are a set of decorators that utilise argparse to simplify the process of accepting and validating input/flags for commands.

pyapp.app.arguments.argument(*name_or_flags, action: str | Type[Action] = None, nargs: int | str = None, const: Any = None, default: Any, type: Type[Any] | None = None, choices: Sequence[Any] = None, required: bool = None, help_text: str = None, metavar: str = None, dest: str = None, completer: BaseCompleter = None)

Decorator for adding arguments to a handler.

This decorator can be used before or after the handler registration decorator CliApplication.command() has been used.

Parameters:
  • name_or_flags – Either a name or a list of option strings, e.g. foo or -f, –foo.

  • action – The basic type of action to be taken when this argument is encountered at the command line.

  • nargs – The number of command-line arguments that should be consumed.

  • const – A constant value required by some action and nargs selections.

  • default – The value produced if the argument is absent from the command line.

  • type – The type to which the command-line argument should be converted.

  • choices – A container of the allowable values for the argument.

  • required – Whether the command-line option may be omitted (optionals only).

  • help_text – A brief description of what the argument does.

  • metavar – A name for the argument in usage messages.

  • dest – The name of the attribute to be added to the object returned by parse_args().

Argument Types

Additional “types” to handle common CLI situations.

class pyapp.app.argument_types.RegexType(regex, message: str = None)[source]

Factory for validating string options against a regular expression.

Instances of RegexType are typically passed as type= arguments to the ArgumentParser add_argument() method or pyApp argument decorator.

Parameters:
  • regex – Regular expression string (or pre-compiled expression)

  • message – Optional message if validation fails, defaults to a simple fallback.

Example of use:

@app.command
@argument("--alpha", type=RegexType(r"[a-z]+"))
def my_command(args: Namespace):
    print(args.option)

@app.command
def my_command(*, alpha: RegexType(r"[a-z]+")):
    print(alpha)

From CLI:

> my_app m_command --alpha abc
abc

New in version 4.2.

Argument Actions

Additional actions to handle common CLI situations.

Key/Value Arguments

class pyapp.app.argument_actions.KeyValueAction(**kwargs)[source]

Action that accepts key/value pairs and appends them to a dictionary.

Example of use:

@app.command
def my_command(options: Mapping[str, str]):
    print(options)

@app.command
@argument("--option", action=KeyValueAction)
def my_command(args: Namespace):
    print(args.option)

From CLI:

> my_app m_command --option a=foo --option b=bar
{'a': 'foo', 'b': 'bar'}

Enum types

class pyapp.app.argument_actions.EnumValue(**kwargs)[source]

Action to use an Enum as the type of an argument. In this mode the Enum is referenced by value.

The choices are automatically generated for help.

Example of use:

class Colour(Enum):
    Red = "red"
    Green = "green"
    Blue = "blue"

@app.command
@argument("--colour", type=Colour, action=EnumValue)
def my_command(args: Namespace):
    print(args.colour)

From CLI:

> my_app m_command --colour red
Colour.Red

New in version 4.2.

class pyapp.app.argument_actions.EnumName(**kwargs)[source]

Action to use an Enum as the type of an argument. In this mode the Enum is referenced by name.

The choices are automatically generated for help.

Example of use:

class Colour(Enum):
    Red = "red"
    Green = "green"
    Blue = "blue"

@app.command
@argument("--colour", type=Colour, action=EnumName)
def my_command(args: Namespace):
    print(args.colour)

From CLI:

> my_app m_command --colour Red
Colour.Red

New in version 4.2.

class pyapp.app.argument_actions.AppendEnumValue(**kwargs)[source]

Action to use an Enum as the type of an argument and to accept multiple enum values. In this mode the Enum is referenced by value.

The choices are automatically generated for help.

Example of use:

class Colour(Enum):
    Red = "red"
    Green = "green"
    Blue = "blue"

@app.command
@argument("--colours", type=Colour, action=AppendEnumValue)
def my_command(args: Namespace):
    print(args.colour)

# Or using typing definition

@app.command
def my_command(*, colours: Sequence[Colour]):
    print(colours)

From CLI:

> my_app m_command --colour red --colour blue
[Colour.Red, Colour.Blue]

New in version 4.9.

class pyapp.app.argument_actions.AppendEnumName(**kwargs)[source]

Action to use an Enum as the type of an argument and to accept multiple enum values. In this mode the Enum is referenced by name.

The choices are automatically generated for help.

Example of use:

class Colour(Enum):
    Red = "red"
    Green = "green"
    Blue = "blue"

@app.command
@argument("--colours", type=Colour, action=AppendEnumName)
def my_command(args: Namespace):
    print(args.colour)

From CLI:

> my_app m_command --colour Red --colour Blue
[Colour.Red, Colour.Blue]

New in version 4.9.

Date and Time types

class pyapp.app.argument_actions.DateAction(option_strings, dest, nargs=None, const=None, default=None, type=None, choices=None, required=False, help=None, metavar=None)[source]

Parse ISO date string.

class pyapp.app.argument_actions.TimeAction(option_strings, dest, nargs=None, const=None, default=None, type=None, choices=None, required=False, help=None, metavar=None)[source]

Parse ISO time string.

class pyapp.app.argument_actions.DateTimeAction(option_strings, dest, nargs=None, const=None, default=None, type=None, choices=None, required=False, help=None, metavar=None)[source]

Parse ISO datetime string.