Skip to main content

`funparse` allows you to 'derive' an argument parser from type annotations of a function's signature, cutting down on the boilerplate code.

Project description

Introduction

funparse allows you to "derive" an argument parser (such as those from argparse) from type annotations of a function's signature, cutting down on the boilerplate code. It's similar to fire in this way, but it's more lightweight and designed in a way to give its user more control over what is going on.

Disclaimer: your user experience may be much richer if you're using a static type checker, such as mypy

Installation

With pip:

pip install funparse[docstring]

With poetry:

poetry install funparse[docstring]

If you don't need to generate per-argument help strings, you can omit the [docstring] extra when installing this package.

Examples

Basic Usage

import sys
import funparse.api as fp

@fp.as_arg_parser
def some_parser_name(
    your_name: str,
    your_age: int,
    pets: list[str] | None = None,
    loves_python: bool = False,
) -> None:
    print("Hi", your_name)

    if pets is not None:
        for pet in pets:
            print("send greetings to", pet, "for me")

    if loves_python:
        print("Cool! I love python too!")


# Run the parser on this set of arguments
some_parser_name.run([
    "Johnny",
    "33",
    "--pets", "Goofy",
    "--pets", "Larry",
    "--pets", "Yes",
    "--loves-python",
])

# You can also use args from the command line
some_parser_name.run(sys.argv)

Printing Help

import funparse.api as fp

@fp.as_arg_parser
def some_parser_name(
    your_name: str,
    your_age: int,
) -> None:
    print("Hi", your_name)
    if your_age > 325:
        print("getting elderly, eh")

# You can print help and usage information like this:
some_parser_name.print_usage()
some_parser_name.print_help()
# These work just like they do on 'argparse.ArgumentParser'

# You can also format this information into strings
usage = some_parser_name.format_usage()
help_str = some_parser_name.format_help()

See more about it here

Behavior on Booleans

import funparse.api as fp

@fp.as_arg_parser
def booler(
    aaa: bool, # This is a positional argument
    bbb: bool = True, # This is a flag which, if present, will set 'bbb' to False
    ccc: bool = False, # This is a flag which, if set, will set 'ccc' to True
) -> None:
    print(aaa, bbb, ccc)

# This will print: True, False, False
booler.run([
    "yes", # 'y', 'true', 'True' and '1' will also work
    "--bbb",
])

# This will print: False, True, False
booler.run([
    "false", # 'n', 'no', 'False' and '0' will also work
])

Behavior on Enums

import funparse.api as fp
import enum


# This Enum functionality will work better if you use SCREAMING_SNAKE_CASE for 
# the names of your enum members (if you don't, your CLI will work in a
# case-sensitive way :P)
class CommandModes(fp.Enum): # You can use enum.Enum and similar classes too
    CREATE_USER = enum.auto()
    LIST_USERS = enum.auto()
    DELETE_USER = enum.auto()


@fp.as_arg_parser
def some_parser(mode: CommandModes) -> None:
    print(f"you picked {mode.name!r} mode!")


some_parser.run(["CREATE_USER"]) # This is valid...
some_parser.run(["create_user"]) # ...so is this...
some_parser.run(["crEatE_usEr"]) # ...and this too...

# This raises an error
some_parser.run(["NON_EXISTING_FUNCTIONALITY"])

Bypassing the command-line

If you want to pass extra data to the function which you're using as your parser generator, but without having to supply this data through the CLI, you can use the ignore parameter on as_arg_parser, like this:

import funparse.api as fp


@fp.as_arg_parser(ignore=["user_count", "user_name"])
def some_parser(
    user_count: int,
    user_name: str,
    user_address: str
    is_foreigner: bool = False,
) -> None:
    print(f"you're the {user_count}th user today! welcome, {user_name}")
    print("They say", user_address, "is lovely this time of the year...")


# These 'state-variables' must be passed as keyword args (or through **kwargs)
some_parser.with_state(
    user_count=33,
    user_name="Josh",
).run(["some address..."])

# If you want, you can cache these parser-with-state objects. It sort of
# reminds me of 'functools.partial'
saving_for_later = some_parser.with_state(
    user_count=33,
    user_name="Josh",
)

# Later:
saving_for_later.run([
    "some address...",
    "--is-foreigner"
])

Using custom argument parsers

import argparse
import funparse.api as fp


# First, subclass 'argparse.ArgumentParser'
class MyParser(argparse.ArgumentParser):
    """Just like argparse's, but better!"""


# Then, pass your parser as an argument to 'as_arg_parser'
@fp.as_arg_parser(parser_type=MyParser)
def some_parser(
    user_name: str,
    is_foreigner: bool = False,
) -> None:
    print("Welcome", user_name)
    if is_foreigner:
        print("Nice to have you here")


# Finally, run your parser. It all works as expected!
some_parser.run([
    "johnny",
    "--is-foreigner",
])

Generating per-argument help strings from docstrings

Thanks to this package, funparse can generate help strings for arguments, from the docstring of the function in question, like this:

import funparse.api as fp

@fp.as_arg_parser(parse_docstring=fp.DocstringStyle.GOOGLE)
def some_parser(
    name: str,
    is_foreigner: bool = False,
) -> None:
    """My awesome command.

    Long description... Aut reiciendis voluptatem aperiam rerum voluptatem non. 
    Aut sit temporibus in ex ut mollitia. Omnis velit asperiores voluptatem ut 
    molestiae quis et qui.

    Args:
        name: some help information about this arg
        is_foreigner: some other help information
    """
    print("Welcome", user_name)
    if is_foreigner:
        print("Nice to have you here")

some_parser.print_help()

The generated command help should look like this:

usage: - [-h] [--is-foreigner] name

Long description... Aut reiciendis voluptatem aperiam rerum voluptatem non.
Aut sit temporibus in ex ut mollitia. Omnis velit asperiores voluptatem ut
molestiae quis et qui.

positional arguments:
  name            some help information about this arg

options:
  -h, --help      show this help message and exit
  --is-foreigner  some other help information (default=False)

Extras

Beyond as_arg_parser, this module also ships:

  • funparse.Enum, which is a subclass of enum.Enum, but with a __str__ that better fits your CLI apps
  • funparse.ArgumentParser, which is a subclass of argparse.ArgumentParser that, unlike the latter, does not terminate your app on (most) exceptions

Have fun!

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

funparse-0.2.4.tar.gz (6.8 kB view details)

Uploaded Source

Built Distribution

funparse-0.2.4-py3-none-any.whl (7.4 kB view details)

Uploaded Python 3

File details

Details for the file funparse-0.2.4.tar.gz.

File metadata

  • Download URL: funparse-0.2.4.tar.gz
  • Upload date:
  • Size: 6.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.5

File hashes

Hashes for funparse-0.2.4.tar.gz
Algorithm Hash digest
SHA256 7664720963c763ad68c8dc88f1790d3eab52287caae0a3c9461106036fc78274
MD5 034c9d480c6896dee0186057e199eb34
BLAKE2b-256 749bbb07781c0675718b2f86742c0d667ad287020267361733eff71a66de7f3d

See more details on using hashes here.

File details

Details for the file funparse-0.2.4-py3-none-any.whl.

File metadata

  • Download URL: funparse-0.2.4-py3-none-any.whl
  • Upload date:
  • Size: 7.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.5

File hashes

Hashes for funparse-0.2.4-py3-none-any.whl
Algorithm Hash digest
SHA256 a9650dd311f8efbe77bfb7637e0da8569caf5ac40931c3eec2f5833cdc787fbb
MD5 16e4630f2a5c39cf63c30e6b00958e08
BLAKE2b-256 3f0d4af9334dae418f70fc9ce6ff91857383c39d42104bfb3a9f8bb6fd0c0cc4

See more details on using hashes here.

Supported by

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