Skip to main content

Easily generate commandline apps from your functions, based on type hints

Project description

clargs

PyPI - Version PyPI - Python Version Tests

The goal of the clargs package is to create command-line interfaces from function signatures.

  • Hit the ground running: With a single line, an existing function is turned into a command line program
  • Extensible: It is flexible enough to do everything that argparse does, and keeps you in control
  • No magic: All the extension does is call commands in argparse; you can log and see these commands
  • Safe: The built-in python argparse module does all the work, so safety guarantees from that module apply
  • Typing: Parameter types are set as PEP 484 type hints (e.g. def foo(bar: int))
  • Standard: By using argparse, you get standard behaviour such as long/short parameters, combine flags, help function
  • Don't repeat yourself: Every parameter is defined (changed, added, removed) in one spot and only one spot, the function definition
  • Rich parameter types: Support for str, int, float, bool, pathlib.Path and typing.Literal (multiple-choice values)
  • Richer parameter types: In addition, lists of these parameters are allowed, default values, boolean-flags (--foo/--no-foo), counts
  • Simple: Pure python, no dependencies
  • Documentation: Function's docstring creates --help documentation. Support for Sphynx, GoogleDoc, NumpyDoc, EpyText

Example

Check out the list of examples to see the package in action

A quick example (just to get you excited):

import clargs


def count(
    singular: str,
    plural: str,
    maxitems: int = 10,
    *,
    shout: bool = False,
):
    """
    Counts from 1 to given number (default = 10)

    This text should not appear

    @param singular: The singular form of the thing to count
    @param plural: The plural form of the thing to count
    @param maxitems: The number to count to
    @param shout: If True, will convert all expressions to capitals
    """
    for i in range(maxitems):
        text = f"{i + 1} {singular if i == 0 else plural}"
        if shout:
            text = text.upper()
        print(text)


if __name__ == "__main__":
    clargs.create_parser_and_run(count)
> python main.py --help
usage: main.py [-h] [--shout [SHOUT]] singular plural [maxitems]

Counts from 1 to given number (default = 10)

positional arguments:
  singular              The singular form of the thing to count
  plural                The plural form of the thing to count
  maxitems              The number to count to

options:
  -h, --help            show this help message and exit
  --shout [SHOUT], -s [SHOUT]
                        If True, will convert all expressions to capitals> python main.py bottle bottles
1 bottle
2 bottles
3 bottles
4 bottles
5 bottles
6 bottles
7 bottles
8 bottles
9 bottles
10 bottles
> python main.py bottle bottles 5 --shout=yes
1 BOTTLE
2 BOTTLES
3 BOTTLES
4 BOTTLES
5 BOTTLES

Supported types

The type of the parameter (given through a type-hint) determines what the input is parsed at. If no type-hint is given, str is assumed.

str, int, float, pathlib.Path

These types just call the constructor on the string (e.g. python main.py --input-file /tmp/myfile.txt --repeat 5 will assign pathlib.Path("/tmp/myfile.txt") to input_file and int("5") to repeat (assuming a function signature like: def run(*, input_file: pathlib.Path, repeat: int)).

bool

Booleans need some special work internally (since bool("False") == True). Any parameter of type bool will accept Yes, No, True and False (case-insensitive) as values. Booleans can also be made Flags, see below under "Extra Types".

typing.Literal["foo", "bar", "baz"]

Using typing.Literal parameters can be made that can only have certain values. The type of the parameters can be any of the types above

list[X] or typing.Sequence[X]

Lists of items is supported (for all pf the above types). For instance a signature of def sum(*, terms: typing.List[float]) -> float means you can use python sum.py --terms 1.2 4 -5

typing.Optional[X] and None | X

typing.Optional or a union with None is ignored, so this won't affect the command line signature.

Extra Types

In addition to normal types, the clargs package defines some special types.

clargs.Flag

Is an alias for bool (should be recognised by static type-checkers). Creates --foo/--no-foo parameter pair to control booleans

clargs.Count

Is an alias for int (should be recognised by static type-checkers). Counts how often a parameter is present (mostly used in --verbose --verbose --verbose parameters)

clargs.ExistingDirectoryPath

Is an alias for pathlib.Path (should be recognised by static type-checkers). It adds validation to confirm that the path is existing, and is a directory.

clargs.ExistingFilePath

Is an alias for pathlib.Path (should be recognised by static type-checkers). It adds validation to confirm that the path is existing, and is a file.

Custom Type

TODO: Describe how to make custom functions.

Validation

Experimental support for validation is added, see this example. There is no clean way yet to give a proper custom error message in case of an exception.

Subparsers

Using subparsers it's possible to add multiple functions to your cli. See an example here

Debug output

clargs uses python's logging module to log to DEBUG level exactly what is being added to argparse's add_argument() function. By making the logger output this to screen, you can debug what's going on.

See an example here

Global Settings

You can control settings on how clargs works, by using the clargs.Clargs class to call your functions.

myclargs = clargs.Clargs(clargs.Settings(...))
myclargs.create_parser_and_run(func)

You can use the following settings (as keyword arguments to Settings)

flag_prefix (default --)

If you want another flag prefix (e.g. ++ or / for windows-like flags), set this here. If you provide your own parser (i.e. you don't use create_parser() on the Clargs object), you need to make sure you set prefix_chars correctly on the parser.

short_flag_prefix (default -)

Same but for the short flags

generate_short_flags (default True)

If true, short flags are generated (so you can use -f instead of --foo. Note that the short flag is only generated for the first parameter starting with a certain letter.

positional_and_kw_args_become (default positional)

Python functions can have positional-only arguments (anything before /), keyword-only arguments (anything after *), and arguments that can be used both positionally and as keywords (default). Positional-only arguments always become positional commandline arguments. Keyword-only arguments always become keyword commandline arguments (flags). This parameter determines what to do with arguments that can be both positional and keyword.

  • positional those arguments are rendered as positional commandline arguments
  • flag those arguments are rendered as keyword commandline arguments (flags)
  • flag_if_default those arguments are rendered as flags if they have a default value, else as positional commandline arguments.

replace_underscore_with_dash (default True)

If false, underscores are not replaced with dashes for the commandline arguments. In the default behaviour, a function parameter foo_bar will become a flag --foo-bar. If this parameter is false, it becomes --foo_bar.

This only affects keyword parameters (flags), and subparser commands (so if a subparser is created for the function count_down, then the commandline command will be count-down.

Compare to other solutions

There are many other solutions to create command line interfaces from functions. I don't think it makes sense to create a comparison list of features now, only to have it be not up to date anymore tomorrow.

The reasons that I developed clargs is because I could not find any solution that made me happy (based on the features and properties I describe above).

License

clargs is distributed under the terms of the MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

clargs-0.9.0.tar.gz (21.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

clargs-0.9.0-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

File details

Details for the file clargs-0.9.0.tar.gz.

File metadata

  • Download URL: clargs-0.9.0.tar.gz
  • Upload date:
  • Size: 21.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.0.0 CPython/3.12.3

File hashes

Hashes for clargs-0.9.0.tar.gz
Algorithm Hash digest
SHA256 ef5235c078750819988968539187d24dcef717503744d02caaffa125e06d6547
MD5 0a49e58f0f7de95fd6ff03bd09ba1569
BLAKE2b-256 44ce7af82905071024f33b8557abf614075007d72f8f24a78a82e7fb0d2050d5

See more details on using hashes here.

File details

Details for the file clargs-0.9.0-py3-none-any.whl.

File metadata

  • Download URL: clargs-0.9.0-py3-none-any.whl
  • Upload date:
  • Size: 13.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.0.0 CPython/3.12.3

File hashes

Hashes for clargs-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 abc010df3074b67cf4e2720afa18e17c6e9c860509c672f53deaea13aa0ede83
MD5 46714269b5e821200a9c90ad61b484ae
BLAKE2b-256 1784d77a9445078fbbe8ce93c3492b1e501fe1e6a1d156f38b03a395dde624c8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page