Installation

As usual, e.g.

] add YAArguParser

Specification

We approximate the Microsoft command-line syntax. Optional arguments are surrounded by square brackets, values are surrounded by angle brackets (chevrons), and mutually exclusive items are separated by a vertical bar.

Usage

Apart from these usage examples (you find the complete sources in the./examples folder), we suggest you also check the the testsuite ./test/runtests.jl .

Example 1 - common usage

We first create an ArgumentParser object, then add and parse our command-line arguments. We will automagically generate a usage string from our key-value store of command-line arguments here, but is also possible to write your own help message instead.

using YAArguParser: ArgumentParser, add_argument!, add_example!, help, parse_args!, args_pairs, generate_usage!

function main()

    ap = ArgumentParser(description="YAArguParser example.", add_help=true)
    add_argument!(ap, "-h", "--help", type=Bool, default=false, description="Help switch.")
    add_argument!(ap, "-i", "--input", type=String, default="filename.txt", description="Input file.")
    add_argument!(ap, "-n", "--number", type=Int, default=0, description="Integer number.")
    add_argument!(ap, "-v", "--verbose", type=Bool, default=false, description="Verbose mode switch.")
    add_example!(ap, "julia $(ap.filename) --input dir/file.txt --number 10 --verbose")
    add_example!(ap, "julia $(ap.filename) --help")

    parse_args!(ap)

    # get all arguments as NamedTuple
    args = NamedTuple(args_pairs(ap))

    # print the usage/help message in magenta if asked for help
    args.help && help(ap, color="magenta")

    # display the arguments
    println(args)

    # DO SOMETHING ELSE

    return 0
end

main()

That is about as simple as it gets and closely follows Python's argparse.

Example 2 - customized help

Now let's define a customized help message:

using YAArguParser

const usage = raw"""
  Usage: main.jl --input <PATH> [--verbose] [--problem] [--help]

  A Julia script with command-line arguments.

  Options:
    -i, --input <PATH>    Path to the input file.
    -v, --verbose         Enable verbose message output.
    -p, --problem         Print the problem statement.
    -h, --help            Print this help message.

  Examples:
    $ julia main.jl --input dir/file.txt --verbose
    $ julia main.jl --help
"""

function main()

    ap = ArgumentParser(description="YAArguParser example.", add_help=true, color="cyan")
    add_argument!(ap, "-h", "--help", type=Bool, default=false, description="Help switch.")
    add_argument!(ap, "-i", "--input", type=String, default="filename.txt", description="Input file.")
    add_argument!(ap, "-n", "--number", type=Int, default=0, description="Integer number.")
    add_argument!(ap, "-v", "--verbose", type=Bool, default=false, description="Verbose mode switch.")
    add_example!(ap, "julia $(ap.filename) --input dir/file.txt --number 10 --verbose")
    add_example!(ap, "julia $(ap.filename) --help")

    # add usage/help text from above
    ap.usage = usage

    parse_args!(ap)

    # print the usage/help message in color defined in ap
    help(ap)

    # DO SOMETHING ELSE

    return 0
end

main()

Example 3 - validating arguments

For Validator details, read Docstrings sections for RealValidator, StrValidator and validate.

using YAArguParser
using YAArguParser: shell_split

function main()

    ap = ArgumentParser(; 
        description="Command line options parser", 
        add_help=true, 
        color = "cyan", 
        )

    add_argument!(ap, "-p", "--plotformat"; 
        type=String, 
        default="PNG",
        description="Accepted file format: PNG (default), PDF, SVG or NONE", 
        validator=StrValidator(; upper_case=true, patterns=["PNG", "SVG", "PDF", "NONE"]),
        )

    add_argument!(ap, "-n", "--number"; 
        type=Int, 
        # an argument with a default value is optional, without - required 
        # default=nothing,
        description="an integer value ranging from 0 to 42", 
        validator=RealValidator{Int}(; incl_ivls=[(0, 42)]),
        )
    
    add_example!(ap, "$(ap.filename) -n 1 --plotformat NONE")
    add_example!(ap, "$(ap.filename) -n 1")
    add_example!(ap, "$(ap.filename) --help")

    # simulate supplied args
    str = "-p SVG -n 33 --help"
    args = shell_split(str)

    parse_args!(ap; cli_args=args)

    # get all arguments as NamedTuple
    args = NamedTuple(args_pairs(ap))

    # print the usage/help message in color defined during initialization, if asked for help
    args.help && help(ap)

    # display the arguments
    println(args)

    # DO SOMETHING with args

    return ap
end

main()

Example 4 - custom parser, initparser

This example shows how to create a customized parser. Here, we create LegacyArgumentParser type which is equivalent to ArgumentParser of SimpleArgParse. You see that by making our type a subtype of AbstractArgumentParser we achieve a flattened access to the struct properties. This is used by initparser function, which simplifies initilalization of nested structs.

using YAArguParser
using YAArguParser: AbstractArgumentParser

@kwdef mutable struct LegacyArgumentParser <: AbstractArgumentParser
    ap::ArgumentParser = ArgumentParser()
    authors::Vector{String} = String[]
    documentation::String = ""
    repository::String = ""
    license::String = ""
end

lp = initparser(LegacyArgumentParser; license="MIT", authors=["Eben60"], description="Example how to extend an argument parser")
@assert lp.ap.description == lp.description

Example 5 - positional arguments, custom validator, initparser

using Dates
using YAArguParser
using YAArguParser: AbstractValidator, warn_and_return
import YAArguParser: validate

@kwdef struct FullAgeValidator <: AbstractValidator
    legal_age::Int = 18
end

function validate(v::Union{AbstractString, Date}, vl::FullAgeValidator)
    birthdate = today()
    try
        birthdate = Date(v)
    catch
        return warn_and_return(v)
    end

    d = day(birthdate)
    m = month(birthdate)
    fullageyear = year(birthdate) + vl.legal_age

    Date(fullageyear, m, d) > today() && return warn_and_return(v)

    return (; ok=true, v=birthdate)
end

function askandget(pp; color=pp.color)
    colorprint(pp.introduction, color)
    colorprint(pp.prompt, color, false; bold=true)
    answer = readline()
    cli_args = Base.shell_split(answer)
    parse_args!(pp; cli_args)
    r = NamedTuple(args_pairs(pp))
    if r.help
        help(pp)
        exit()
    end
    r.abort && exit()
    return r
end

function main()

    color = "cyan"
    prompt = "legal age check> "

    ask_full_age = let
        pp = initparser(InteractiveArgumentParser;  
            description="Asking if one is of full age", 
            add_help=true, 
            color = color,
            introduction="Are you of full legal age? Please type y[es] or n[o] and press <ENTER>",
            throw_on_exception = true,
            prompt=prompt,
            )

        add_argument!(pp, "-y", "--yes_no"; 
            type=String, 
            positional=true,
            description="Asking about legal age",
            validator=StrValidator(; upper_case=true, starts_with=true, patterns=["yes", "no"]),
            )
    
        add_argument!(pp, "-a", "--abort", 
            type=Bool, 
            default=false,
            description="Abort?",
            )   
        
        add_example!(pp, "$(pp.prompt) y")
        add_example!(pp, "$(pp.prompt) --abort")
        add_example!(pp, "$(pp.prompt) --help")
        pp
    end

    check_full_age = let
        pp = initparser(InteractiveArgumentParser; 
            description="Checking if one is of full age", 
            add_help=true, 
            color=color, 
            throw_on_exception = true,
            introduction="Please enter your birth date in the yyyy-mm-dd format",
            prompt=prompt,
            )

        add_argument!(pp, "-d", "--birthdate"; 
            type=Date, 
            positional=true,
            description="Asking about legal age",
            validator=FullAgeValidator(),
            )
    
        add_argument!(pp, "-a", "--abort", 
            type=Bool, 
            default=false, 
            description="Abort?",
            )   
        
        add_example!(pp, "$(pp.prompt) 2000-02-29")
        add_example!(pp, "$(pp.prompt) --abort")
        add_example!(pp, "$(pp.prompt) --help")
        pp
    end

    (; yes_no ) = askandget(ask_full_age)
    yes = (yes_no == "YES")
    yes || return false

    (; birthdate) = askandget(check_full_age )
    println("You appear to be of full age.")

    return true
end

main()

Dates package extension

This is to parse various date and time formats. By default it will return different type (DateTime, Date, or Time), depending on the user's input, e.g. "2024-12-31" will be returned as Date, and "2024-12-31 23:59" as DateTime for the same argument.

For formats supported out of the box, see the source code of specify_datetime_fmts function in ext/ParseDatesExt.jl. For usage, see also file test/test_datetime.jl.

You also can add or redefine accepted formats - see file test/test_owndateformat.jl.