Convert Figma logo to code with AI

google logoargh

Rust derive-based argument parsing optimized for code size

1,626
86
1,626
64

Top Related Projects

7,933

Create *beautiful* command-line interfaces with Python

15,330

Typer, build great CLIs. Easy to code. Based on Python type hints.

15,496

Python composable command line interface toolkit

A non-validating SQL parser module for Python

Quick Overview

Argh is a Python library that simplifies command-line argument parsing. It provides a user-friendly interface for creating command-line interfaces (CLIs) with minimal boilerplate code, making it easier for developers to build robust CLI applications.

Pros

  • Simple and intuitive API, reducing the learning curve for developers
  • Automatic generation of help messages and usage information
  • Supports both positional and named arguments with minimal configuration
  • Seamlessly integrates with existing Python functions and methods

Cons

  • Limited advanced features compared to more comprehensive libraries like argparse
  • May not be suitable for extremely complex CLI applications with intricate argument structures
  • Less actively maintained compared to some alternative libraries
  • Documentation could be more extensive and up-to-date

Code Examples

  1. Basic usage:
from argh import arg, dispatch_command

@arg('name', help='Your name')
@arg('--greeting', help='Greeting to use', default='Hello')
def greet(name, greeting='Hello'):
    return f"{greeting}, {name}!"

if __name__ == '__main__':
    dispatch_command(greet)
  1. Multiple commands:
from argh import arg, dispatch_commands

def add(a: int, b: int):
    return a + b

@arg('--uppercase', help='Convert to uppercase')
def echo(text: str, uppercase=False):
    return text.upper() if uppercase else text

if __name__ == '__main__':
    dispatch_commands([add, echo])
  1. Nested commands:
from argh import arg, dispatch_command

def main():
    pass

@arg('name', help='Repository name')
def create(name):
    return f"Created repository: {name}"

main.create = create

if __name__ == '__main__':
    dispatch_command(main)

Getting Started

To get started with Argh, first install it using pip:

pip install argh

Then, create a Python file (e.g., cli.py) with your command-line interface:

from argh import arg, dispatch_command

@arg('name', help='Your name')
def greet(name):
    return f"Hello, {name}!"

if __name__ == '__main__':
    dispatch_command(greet)

Run your CLI application:

python cli.py John

This will output: "Hello, John!"

Competitor Comparisons

7,933

Create *beautiful* command-line interfaces with Python

Pros of docopt

  • Declarative approach using POSIX-style usage patterns
  • Automatically generates help messages from the usage patterns
  • Supports a wide range of programming languages beyond Python

Cons of docopt

  • Less flexible for complex command-line interfaces
  • May require more verbose usage patterns for intricate options
  • Limited built-in type validation and conversion

Code Comparison

docopt:

"""Naval Fate.

Usage:
  naval_fate ship new <name>...
  naval_fate ship <name> move <x> <y> [--speed=<kn>]
  naval_fate ship shoot <x> <y>
  naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
  naval_fate -h | --help
  naval_fate --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.
"""

argh:

@argh.arg('--speed', default=10)
@argh.arg('name', nargs='+')
def ship_new(name):
    pass

@argh.arg('--speed', default=10)
def ship_move(name, x, y, speed=10):
    pass

parser = argh.ArghParser()
parser.add_commands([ship_new, ship_move])
15,330

Typer, build great CLIs. Easy to code. Based on Python type hints.

Pros of Typer

  • Modern Python features: Utilizes type hints and async support
  • Rich CLI features: Offers advanced features like subcommands and option groups
  • Extensive documentation: Provides detailed guides and examples

Cons of Typer

  • Steeper learning curve: More complex API compared to Argh's simplicity
  • Heavier dependencies: Relies on FastAPI and its ecosystem

Code Comparison

Typer:

import typer

app = typer.Typer()

@app.command()
def hello(name: str):
    typer.echo(f"Hello {name}")

if __name__ == "__main__":
    app()

Argh:

from argh import arg, dispatch_command

@arg('name')
def hello(name):
    print(f"Hello {name}")

if __name__ == '__main__':
    dispatch_command(hello)

Summary

Typer offers more advanced features and modern Python support, making it suitable for complex CLI applications. Argh, on the other hand, provides a simpler and more lightweight approach, ideal for quick and straightforward command-line tools. The choice between the two depends on the project's requirements and the developer's preference for simplicity versus feature-richness.

15,496

Python composable command line interface toolkit

Pros of Click

  • More comprehensive and feature-rich, offering advanced functionality like subcommands and option groups
  • Extensive documentation and a larger community, providing better support and resources
  • Built-in support for generating command-line help messages and auto-completion

Cons of Click

  • Steeper learning curve due to its more complex API and extensive features
  • Slightly more verbose syntax for simple use cases
  • Larger dependency footprint compared to Argh's lightweight approach

Code Comparison

Click:

import click

@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name', help='The person to greet.')
def hello(count, name):
    for _ in range(count):
        click.echo(f"Hello, {name}!")

Argh:

from argh import arg, dispatch_command

@arg('--name', help='The person to greet')
@arg('-c', '--count', default=1, help='Number of greetings')
def hello(name, count=1):
    for _ in range(count):
        print(f"Hello, {name}!")

dispatch_command(hello)

Both libraries offer similar functionality, but Click provides a more structured approach with decorators, while Argh aims for simplicity and minimal boilerplate code.

A non-validating SQL parser module for Python

Pros of sqlparse

  • Specialized for SQL parsing and formatting
  • More comprehensive SQL support with features like statement splitting
  • Actively maintained with regular updates

Cons of sqlparse

  • Limited to SQL-specific functionality
  • Steeper learning curve for non-SQL-related tasks
  • Larger codebase and potentially slower for simple parsing tasks

Code Comparison

sqlparse example:

import sqlparse

sql = "SELECT * FROM table WHERE id = 1"
formatted = sqlparse.format(sql, reindent=True, keyword_case='upper')
print(formatted)

argh example:

from argh import arg, dispatch_command

@arg('name', help='Your name')
def greet(name):
    return f"Hello, {name}!"

dispatch_command(greet)

Summary

sqlparse is a specialized library for SQL parsing and formatting, offering comprehensive SQL support. It's ideal for projects heavily focused on SQL manipulation. argh, on the other hand, is a general-purpose command-line argument parsing library, providing a simpler interface for creating command-line tools. While sqlparse excels in SQL-related tasks, argh offers broader applicability for various command-line applications.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Argh

Argh is an opinionated Derive-based argument parser optimized for code size

crates.io license docs.rs Argh

Derive-based argument parsing optimized for code size and conformance to the Fuchsia commandline tools specification

The public API of this library consists primarily of the FromArgs derive and the from_env function, which can be used to produce a top-level FromArgs type from the current program's commandline arguments.

Basic Example

use argh::FromArgs;

#[derive(FromArgs)]
/// Reach new heights.
struct GoUp {
    /// whether or not to jump
    #[argh(switch, short = 'j')]
    jump: bool,

    /// how high to go
    #[argh(option)]
    height: usize,

    /// an optional nickname for the pilot
    #[argh(option)]
    pilot_nickname: Option<String>,
}

fn main() {
    let up: GoUp = argh::from_env();
}

./some_bin --help will then output the following:

Usage: cmdname [-j] --height <height> [--pilot-nickname <pilot-nickname>]

Reach new heights.

Options:
  -j, --jump        whether or not to jump
  --height          how high to go
  --pilot-nickname  an optional nickname for the pilot
  --help, help      display usage information

The resulting program can then be used in any of these ways:

  • ./some_bin --height 5
  • ./some_bin -j --height 5
  • ./some_bin --jump --height 5 --pilot-nickname Wes

Switches, like jump, are optional and will be set to true if provided.

Options, like height and pilot_nickname, can be either required, optional, or repeating, depending on whether they are contained in an Option or a Vec. Default values can be provided using the #[argh(default = "<your_code_here>")] attribute, and in this case an option is treated as optional.

use argh::FromArgs;

fn default_height() -> usize {
    5
}

#[derive(FromArgs)]
/// Reach new heights.
struct GoUp {
    /// an optional nickname for the pilot
    #[argh(option)]
    pilot_nickname: Option<String>,

    /// an optional height
    #[argh(option, default = "default_height()")]
    height: usize,

    /// an optional direction which is "up" by default
    #[argh(option, default = "String::from(\"only up\")")]
    direction: String,
}

fn main() {
    let up: GoUp = argh::from_env();
}

Custom option types can be deserialized so long as they implement the FromArgValue trait (automatically implemented for all FromStr types). If more customized parsing is required, you can supply a custom fn(&str) -> Result<T, String> using the from_str_fn attribute:

use argh::FromArgs;

#[derive(FromArgs)]
/// Goofy thing.
struct FiveStruct {
    /// always five
    #[argh(option, from_str_fn(always_five))]
    five: usize,
}

fn always_five(_value: &str) -> Result<usize, String> {
    Ok(5)
}

Positional arguments can be declared using #[argh(positional)]. These arguments will be parsed in order of their declaration in the structure:

use argh::FromArgs;

#[derive(FromArgs, PartialEq, Debug)]
/// A command with positional arguments.
struct WithPositional {
    #[argh(positional)]
    first: String,
}

The last positional argument may include a default, or be wrapped in Option or Vec to indicate an optional or repeating positional argument.

Subcommands are also supported. To use a subcommand, declare a separate FromArgs type for each subcommand as well as an enum that cases over each command:

use argh::FromArgs;

#[derive(FromArgs, PartialEq, Debug)]
/// Top-level command.
struct TopLevel {
    #[argh(subcommand)]
    nested: MySubCommandEnum,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum MySubCommandEnum {
    One(SubCommandOne),
    Two(SubCommandTwo),
}

#[derive(FromArgs, PartialEq, Debug)]
/// First subcommand.
#[argh(subcommand, name = "one")]
struct SubCommandOne {
    #[argh(option)]
    /// how many x
    x: usize,
}

#[derive(FromArgs, PartialEq, Debug)]
/// Second subcommand.
#[argh(subcommand, name = "two")]
struct SubCommandTwo {
    #[argh(switch)]
    /// whether to fooey
    fooey: bool,
}

NOTE: This is not an officially supported Google product.

How to debug the expanded derive macro for argh

The argh::FromArgs derive macro can be debugged with the cargo-expand crate.

Expand the derive macro in examples/simple_example.rs

See argh/examples/simple_example.rs for the example struct we wish to expand.

First, install cargo-expand by running cargo install cargo-expand. Note this requires the nightly build of Rust.

Once installed, run cargo expand with in the argh package and you can see the expanded code.