GithubHelp home page GithubHelp logo

nim-argparse's Introduction

argparse

tests

Docs

Command line argument parsing library. It generates the parser at compile time so that parsed options have a well-defined type.

Example

After defining your expected arguments with newParser(...), use:

  1. run(...) to parse and execute any run: blocks you've defined. This will automatically display help text when -h/--help is used.
  2. parse(...) to parse without executing, giving you more control over what happens.

Both procs will parse the process' command line if no arguments are given.

See the docs for more info

run()

import argparse

var p = newParser:
  flag("-a", "--apple")
  flag("-b", help="Show a banana")
  option("-o", "--output", help="Output to this file")
  command("somecommand"):
    arg("name")
    arg("others", nargs = -1)
    run:
      echo opts.name
      echo opts.others
      echo opts.parentOpts.apple
      echo opts.parentOpts.b
      echo opts.parentOpts.output
      echo opts.parentOpts.output_opt.get()

try:
  p.run(@["--apple", "-o=foo", "somecommand", "myname", "thing1", "thing2"])
except UsageError as e:
  stderr.writeLine getCurrentExceptionMsg()
  quit(1)

parse()

import argparse

var p = newParser:
  flag("-a", "--apple")
  flag("-b", help="Show a banana")
  option("-o", "--output", help="Output to this file")
  arg("name")
  arg("others", nargs = -1)

try:
  var opts = p.parse(@["--apple", "-o=foo", "hi"])
  assert opts.apple == true
  assert opts.b == false
  assert opts.output == "foo"
  assert opts.name == "hi"
  assert opts.others == @[]
except ShortCircuit as err:
  if err.flag == "argparse_help":
    echo err.help
    quit(1)
except UsageError:
  stderr.writeLine getCurrentExceptionMsg()
  quit(1)

Alternatives

If argparse doesn't suit your needs, consider these alternatives:

nim-argparse's People

Contributors

iffy avatar krux02 avatar luav avatar metagn avatar solitudesf avatar zoomrmc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

nim-argparse's Issues

Required options

Another feature that I'm missing (unless I'm missing something ;)) is to have required options. As far as I can see mandatory arguments are currently only possible as positional arguments. I often prefer options like -i/--input/-o/--output/--important-param over positional arguments for their explicitness and positional independence.

Skip main run path if subcommands are present

First off, thanks for a great library!

When using parser.run, I would like to be able to not run the main run block when a subcommand is called. For example, in the following setup:

import argparse

var p = newParser("demo"):
  command("subcommand"):
    run:
      echo "in subcommand"
  run:
    echo "in main"

p.run(@["subcommand"])
p.run(@[])

I would like there to be a way for the output to be

in subcommand
in main

(Currently, it shows in main / in subcommand / in main.)

Is this currently possible, or would it be possible to add?

Thanks!

With parse(), no way to print help for subcommand

var p = newParser:
  command "foo":
    flag("-a")
  command "bar":
    flag("-b")
try:
  var opts = p.parse(@["foo", "--help"])
except ShortCircuit as e:
  if e.flag == "argparse_help":
    echo p.help # how do I get p.fooParser.help or know that they passed in foo?

Required options override ShortCircuits when calling parse()

I wonder if parse should raise ShortCircuit when one is encountered, rather than having people check for .help == true?

  test "required options still allow for --help":
    var p = newParser:
      option("-b", required=true)
    expect ShortCircuit:
      discard p.parse(shlex"--help")

`required=true` causes an error if the option is set using an environment variable

Hey there,

Recently started using argparse. Works great so far, but I have a small issue: I have an option defined as this:

let p = newParser:
  command("run"):
    option("--token", help="App token", env="APP_TOKEN", required=true)
    run:
      discard

try:
  p.run()
except UsageError as e:
  stderr.writeLine getCurrentExceptionMsg()
  quit(1)

If I set APP_TOKEN to some non-empty value, I expect my program to run. But instead I'm getting an error: "Option --fbx-token is required and was not provided".

Would it be possible to fix that?

Thanks a lot! 🙂

There are sometimes conflicts with procs named `run`

import argparse
proc run(args: varargs[string]) = discard
let p = newParser("foo"):
  run:
    echo $opts
p.run()

Fails to compile:

/private/tmp/samp.nim(6, 18) template/generic instantiation of `newParser` from here
/private/tmp/samp.nim(8, 11) Error: undeclared identifier: 'opts'

Which type to use when passing `optsIdent` to a function?

Hi I was wondering which type I should use to pass the arguments around, something like this:

proc some_run_func(opts: WhatShouldThisTypeBe?): void =
  echo opts

var parser = newParser("server"):
  flag("-p", "--preload", help="Should we preload data")

try:
  some_run_func(parser.parse())
except UsageError:
  echo parser.help
  stderr.writeLine getCurrentExceptionMsg()
  quit(1)

`Error: undeclared identifier: 'opts'` when prologue is imported

I encountered a weird bug. Consider the following code:

import os

import argparse
import prologue

var p = newParser:
  flag("-v", "--version", help="Print version info and quit")
  run:
    if opts.version:
      echo "0.1.0"
      quit(0)
    echo "work"

try:
  p.run(commandLineParams())
except UsageError:
  stderr.writeLine getCurrentExceptionMsg()
  quit(1)

This does not compile due to Error: undeclared identifier: 'opts'. The strange part is, this error only occurs when prologue is imported. If you comment out import prologue the code works fine. Not sure what to make of it :/

$ nim --version
Nim Compiler Version 1.6.6 [Windows: amd64]
Compiled at 2022-05-05
Copyright (c) 2006-2021 by Andreas Rumpf

active boot switches: -d:release

argparse version: 3.0.0
prologue version: 0.6.0

options are removed under -d:danger -d:release

HI there,

I have some code that when compiled with optimisations and checks off it simply disregards their declaration.

image

That is in a debug build.

image

This is with an optimised build.

The code in question:

when declared(commandLineParams):
    var cliArgs = commandLineParams()

# Parse Arguments
var p = newParser("mosh"):
    help("mosh can turn any input file into audio files in the wav format.")
    option("-b", "--depth", choices = @["8","16","24","32"], default="8", help="Bit-depth of the output file.")
    option("-c", "--channels", default="1", help="Number of channels in the output file.")
    option("-r", "--rate", default="44100", help="The sampleing rate of the output file.")
    option("-l", "--limit", default="5000", help="The maximum limit of files to process in directory mode.")
    option("-m", "--maxsize", default="5000", help="The maximum size of an individual file to be processed in directory mode.")
    option("-dc", "--dcfilter", default="1", help="Applies a dcfilter to the output. 1 for on (default or 0 for off.")
    flag("-v", "--verbose", help="When enabled, allows for verbose output.")
    arg("input")
    arg("output")
var opts = p.parse(cliArgs)

Don't convert option values to string

Values for options get automatically converted to "" even if the user has not passed any value,
this makes it impossible to detect if the user has passed an empty string to the cli.

It would be neat to get a way to access the original Option so we can be more explicit.

Something like this

var p = newParser:
  command("command"):
    option("--foo")
    run:
      assert: opts.fooOpt == none[string]

group order

Is there a way to set the ordering of grouped commands?

I cannot figure out how the ordering of groups is determined.

Thanks

Detect stdin in non-interactive environment.

I am trying to write a a CLI that can take stdin or read from a file.

Most tools allow this syntax:

# stdin
cat tests/fastq/dup.fq | sc --debug fq-dedup

# alternative stdin with explicit "-" to indicate stdin
cat tests/fastq/dup.fq | sc --debug fq-dedup - 

# specify file directly
sc --debug fq-dedup  tests/fastq/dup.fq

I was able to come up with a workaround to get this to work locally. I use terminal.isatty(stdin) to detect whether input is coming from stdin, but it would be more convenient if argparse could make this distinction.

In other words, is there a way to specify whether stdin is allowed for an argument, and have nim-argparse handle parsing of this or detect stdin?

On a related note, terminal.isatty() does not appear to work in non-interactive environments. Any idea what is going on there?

Command Groups

Have you considered allowing command groups?

    command("command"):
        arg("parse", nargs=1, group="data", help="parse data")
        arg("fetch", nargs=1, group="api",help="fetch data")

Would render as:

Usage:
  command [options] <arg>

data:
  parse             parse data

api:
  fetch              fetch data

help() procedure only takes a constant string

help() procedure only takes a constant string, but what if I want to change help text depending on the situation? Example:

var helpText = "..."

if not trueColorSupport:
  helpText &= "\nWARNING: your terminal emulator does not support true colors"

var parser = newParser:
  help(helpText)
  ...

bug: no way to supply default values for options set as multiple

there's a bug in argparse which won't let me supply default values for an option that i set as multiple. here's a small poc which will error:

import argparse

var p = newParser:
  option("-H", "--header", default=some(@["Content-Type: application/json"]), help="specify headers", multiple=true)
try:
    let parsedArgs = p.parse(commandLineParams())

    echo parsedArgs.header
except UsageError as e:
  stderr.writeLine getCurrentExceptionMsg()
  quit(1)
Error: type mismatch: got <string, string, default: Option[seq[string]], help: string, multiple: bool>
but expected one of:
proc option(name1: string; name2 = ""; help = ""; default = none[string]();
            env = ""; multiple = false; choices: seq[string] = @[];
            required = false; hidden = false)
  first type mismatch at position: 3
  required type for default: Option[system.string]
  but expression 'default = some(@["Content-Type: application/json"])' is of type: Option[seq[string]]
proc option[T](val: sink T): Option[T]
  first type mismatch at position: 2
  extra argument given

expression: option("-H", "--header", default = some(@["Content-Type: application/json"]),

If I change default to default=some("Content-Type: application/json"), the error will change:

Error: type mismatch: got 'string' for '"Content-Type: application/json"' but expected 'seq[string]'

Everything works as expected if I don't supply default

nim-argparse fails on recent devel

nimble test endswith the following traceback:

/home/brentp/src/nim-argparse/src/argparse/macrohelp.nim(4, 8) Warning: imported and not used: 'sequtils' [UnusedImport]
/home/brentp/src/nim-argparse/src/argparse.nim(651, 9) Hint: 'ParentOptsIdent' is declared but not used [XDeclaredButNotUsed]
/home/brentp/src/nim-argparse/src/argparse.nim(117, 3) Hint: 'ParseResult' is declared but not used [XDeclaredButNotUsed]
stack trace: (most recent call last)
/home/brentp/src/nim-argparse/src/argparse.nim(929, 23) tmpmkParser
/home/brentp/src/nim-argparse/src/argparse.nim(760, 31) mkParser
/home/brentp/src/nim-argparse/src/argparse.nim(623, 36) genParseProcs
/home/brentp/src/nim-argparse/src/argparse/macrohelp.nim(60, 8) parentOf
/home/brentp/src/nim-argparse/tests/test1.nim(24, 7) template/generic instantiation of `suite` from here
/home/brentp/src/nim-argparse/tests/test1.nim(25, 8) template/generic instantiation of `test` from here
/home/brentp/src/nim-argparse/tests/test1.nim(26, 22) template/generic instantiation of `newParser` from here
/home/brentp/src/nim-argparse/src/argparse/macrohelp.nim(60, 8) Error: node not found: EXTRA
     Error: Execution failed with exit code 1
        ... Command: "/home/brentp/src/nim/bin/nim" c --noNimblePath "-r" "--path:."  "/home/brentp/src/nim-argparse/tests/test1.nim"

Add docs describing output type of parse

While the docs outline the most basic usage, I was trying to put the try-except for the call to parse inside a proc and return the result... but have no not been able to do better than return a ref untyped.

I see an issue referring to an OptsArgparse type when I used the wrong type, but OptsArgparse isn't defined either.

Could you provide guidance (and ideally docs) on what the return of parse is?

Support custom short-circuited flags (like how --help works)

run() does not return anything, but flag() cannot have a run: action attached to it.

So, for example, consider a --version flag. It is natural to write something like this:

var p = newParser("syms"):
  flag("-V", "--version", help="show program's version number and exit")

let opts = p.parse()
if opts.version:
  echo "foo version 0.1"

But then if I have run actions, they will not be executed. On the other hand, if I replace

let opts = p.parse()

with

p.run()

then I cannot test whether --version was given later. And I cannot write:

var p = newParser("syms"):
  flag("-V", "--version", help="show program's version number and exit"):
    run:
      echo "foo version 0.1"

p.run()

So I am unsure how run: actions are supposed to be mixed with option parsing…I'm new to Nim, so I guess I've probably overlooked something. Thanks for argparse!

Treatment of `--help` is a bit confusing

It is not obvious that the built-in implementation of --help does not exit the program, so this is up to the author. This is actually quite useful, as it makes it easy to add extra material after the auto-generated output.

Also, it is not obvious that if you use nohelpflag() and then define a --help flag anyway, it will reactivate the built-in output. It seems not to be possible to override the built-in output altogether.

Exception on `-h` | `--help`

import argparse
let
  p = newParser("test"): discard
  opts = p.parse

with this minimal program will output the help contents and throw Error: unhandled exception: [ShortCircuit] when program invoked with any help flag. Am i missing something?

Cannot have a non-constant string name for a parser

Making a parser for a program, it is natural to use the program's name as the name of the parser, and it is conventional to get this name from argv[0], so something like:

import system
let progName = lastPathPart(getAppFilename())

But progName cannot be passed as an argument to newParser() (unless I've misunderstood!).

Add group option for arguments

In the similarly named Python module there is a group feature for arguments similar to the command groups introduced in #14.
The Python module also has a great extra feature mutually exclusive group, which by the way also allows to add both commands and arguments to one group.
Would you be willing to add these features (groups; mutually exclusive groups; allow combining arguments/commands in a group)to your module?
Thank you

FR: allow marking args/flags/options as global or exclusive to no subcommands

It would be very useful to be able to have two types of arguments/flags/options:

  1. Common to all invocations of the program, including all subcommands or no subcommands
  2. Conflicting with any subcommands

Syntax proposal:

var p = newParser:
  flag("-n", "--dryrun") # common
  rootCommand:
    arg("input") # can't be used with `frobnicate`
  command("frobnicate"):
    flag("-b")
    arg("subcommandInput")

Support for type converters / custom validators?

First of all: Great project! Finally writing CLIs will become convenient in Nim ;).

I was wondering if it is possible to have type converters / custom validators similar to Python/argparse's type that can be used for use cases like:

  • Specify that a certain argument needs to be a valid float.
  • Ensure that a certain argument is e.g. an even integer.

It would be nice if these use cases would not require a manual post-parsers validation + convert. Is that already possible?

Restore support for 1.0.x

Error: execution of an external compiler program 'clang -c  -w  -I/Users/matt/.choosenim/toolchains/nim-1.0.10/lib -I/Users/matt/m/nim-argparse/tests -o /Users/matt/.cache/nim/test1_d/@mtest1.nim.c.o /Users/matt/.cache/nim/test1_d/@mtest1.nim.c' failed with exit code: 1

/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:5850:15: error: no member named 'apple' in 'struct tyObject_Optssomename__RlCupyh3s227sVmILhSBQg'
                                                (*opts).apple = NIM_TRUE;
                                                ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:5860:15: error: no member named 'banana' in 'struct tyObject_Optssomename__RlCupyh3s227sVmILhSBQg'
                                                (*opts).banana = NIM_TRUE;
                                                ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:6159:15: error: no member named 'apple' in 'struct tyObject_Optssomename__RlCupyh3s227sVmILhSBQg'
                                                (*opts).apple = NIM_TRUE;
                                                ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:6169:15: error: no member named 'banana' in 'struct tyObject_Optssomename__RlCupyh3s227sVmILhSBQg'
                                                (*opts).banana = NIM_TRUE;
                                                ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:7582:22: error: no member named 'apple' in 'struct tyObject_Optssomename__RlCupyh3s227sVmILhSBQg'
                                                T36_ = (*opts).apple; (*opts).apple = copyStringRC1((*T35_));
                                                       ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:7582:37: error: no member named 'apple' in 'struct tyObject_Optssomename__RlCupyh3s227sVmILhSBQg'
                                                T36_ = (*opts).apple; (*opts).apple = copyStringRC1((*T35_));
                                                                      ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:8875:17: error: no member named 'b' in 'struct tyObject_Optsprog__1hHWPJAzEpvZ9a30IS0xfKw'
                T2_ = (*opts).b; (*opts).b = copyStringRC1(((NimStringDesc*) &TM__SwXGXvlvxAhMrH9cOP57dNQ_385));
                      ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:8875:28: error: no member named 'b' in 'struct tyObject_Optsprog__1hHWPJAzEpvZ9a30IS0xfKw'
                T2_ = (*opts).b; (*opts).b = copyStringRC1(((NimStringDesc*) &TM__SwXGXvlvxAhMrH9cOP57dNQ_385));
                                 ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:9076:22: error: no member named 'b' in 'struct tyObject_Optsprog__1hHWPJAzEpvZ9a30IS0xfKw'
                                                T55_ = (*opts).b; (*opts).b = copyStringRC1((*T54_));
                                                       ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:9076:33: error: no member named 'b' in 'struct tyObject_Optsprog__1hHWPJAzEpvZ9a30IS0xfKw'
                                                T55_ = (*opts).b; (*opts).b = copyStringRC1((*T54_));
                                                                  ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:10767:47: error: no member named 'name' in 'struct tyObject_Optsprog__1hHWPJAzEpvZ9a30IS0xfKw'
                setOrAdd__6hK8HqjuV9cQ3ZfXC6zIOEA((&(*opts).name), T5_);
                                                    ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:11374:47: error: no member named 'only' in 'struct tyObject_Optssomething__bn7HPyWyoRVXfmyDgbrLfg'
                setOrAdd__6hK8HqjuV9cQ3ZfXC6zIOEA((&(*opts).only), T5_);
                                                    ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:11661:47: error: no member named 'name' in 'struct tyObject_Optsprog__1hHWPJAzEpvZ9a30IS0xfKw'
                setOrAdd__6hK8HqjuV9cQ3ZfXC6zIOEA((&(*opts).name), T4_);
                                                    ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:11692:17: error: no member named 'name' in 'struct tyObject_Optsprog__1hHWPJAzEpvZ9a30IS0xfKw'
                T2_ = (*opts).name; (*opts).name = copyStringRC1(((NimStringDesc*) &TM__SwXGXvlvxAhMrH9cOP57dNQ_309));
                      ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:11692:31: error: no member named 'name' in 'struct tyObject_Optsprog__1hHWPJAzEpvZ9a30IS0xfKw'
                T2_ = (*opts).name; (*opts).name = copyStringRC1(((NimStringDesc*) &TM__SwXGXvlvxAhMrH9cOP57dNQ_309));
                                    ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:11970:47: error: no member named 'name' in 'struct tyObject_Optsprog__1hHWPJAzEpvZ9a30IS0xfKw'
                setOrAdd__6hK8HqjuV9cQ3ZfXC6zIOEA((&(*opts).name), T4_);
                                                    ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:11991:30: error: no member named 'name' in 'struct tyObject_Optsprog__1hHWPJAzEpvZ9a30IS0xfKw'
                asgnRef((void**) (&(*opts).name), getEnv__hhED57tMl0Iaa5bOg9cJaig(((NimStringDesc*) &TM__SwXGXvlvxAhMrH9cOP57dNQ_660), ((NimStringDesc*) &TM__SwXGXvlvxAhMrH9cOP57dNQ_309)));
                                   ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:12304:47: error: no member named 'name' in 'struct tyObject_Optsprog__1hHWPJAzEpvZ9a30IS0xfKw'
                setOrAdd__6hK8HqjuV9cQ3ZfXC6zIOEA((&(*opts).name), T7_);
                                                    ~~~~~~~ ^
/Users/matt/.cache/nim/test1_d/@mtest1.nim.c:12307:47: error: no member named 'age' in 'struct tyObject_Optsprog__1hHWPJAzEpvZ9a30IS0xfKw'
                setOrAdd__6hK8HqjuV9cQ3ZfXC6zIOEA((&(*opts).age), T8_);
                                                    ~~~~~~~ ^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.

Question: Is it possible to disable/remove leading hyphen for a specific command?

Hello!
I'm wondering if it's possible to disable or remove the leading hyphen (- or --) when using nim-argparse? For example, instead of doing mycmd --help, is it possible to parse arguments like mycmd help? Quite a stupid question, but I couldn't find a direct note on this in the docs. Although there's a test folder I wouldn't be able to sort it out.

Thank you.

Deprecation warning on nim 1.6.2

...\.nimble\pkgs\argparse-2.0.1\argparse\backend.nim(490, 48) template
/generic instantiation of `popleft` from here
...\.nimble\pkgs\argparse-2.0.1\argparse\backend.nim(165, 5) Warning:
use `delete(s, first..last)`; delete is deprecated [Deprecated]

undeclared field in backend when using arg() with hyphens in the arg name

In the following example:

import argparse

discard newParser:
  arg("some-stuff")

I am seeing the following error on version 3.0.1:

/home/kyle/dev/dbTransfer/example.nim(3, 9) template/generic instantiation of `newParser` from here
/home/kyle/.nimble/pkgs/argparse-3.0.1/argparse/backend.nim(512, 17) Error: undeclared field: 'some-stuff'

Hyphens in general are handled pretty inconsistently; for example, they are translated to underscores (I think?) in option(), but not in command(), requiring you to escape the field name with backticks in that case.

IndexError when option is missing argument

Behavior

You specify a parser with an option argument. E.g.

var argparser = newParser("my prog"):
    option("-f", "--file", multiple=false, help="File to process")
run:
    ...

If you call this program with

argparser.run(commandLineParams())

and then only supply e.g. the option "-f" you get an IndexError.

Expected Behavior

Instead of an index error print a help message that the option is missing a value.

FR: Provide user-defined short-circuiting, (allows `--version`)

A user defined error flag for short-circuiting, such as "argparse_help" would be nice, as it could allow react to a flag/command. Currently it looks like you can't ignore the absence of positional arguments and act on a flag, such as -v/--version.
At the very least a hardcoded "argparse_version" is enough to get by.

Importing argparse breaks std/logging

Don't really know if I should be reporting this in the Nim repo or here. However, if I import this library, I'm unable to use the std/logging library.

import std/logging, argparse

addHandler newConsoleLogger()

error "not working"

Compiling this results in:

$ nim c --out:"bin/test" -r "~/Documents/monorepo-manager/pkgs/mono/test.nim"
Hint: used config file '~/.choosenim/toolchains/nim-1.6.2/config/nim.cfg' [Conf]
Hint: used config file '~/.choosenim/toolchains/nim-1.6.2/config/config.nims' [Conf]
Hint: used config file '~/Documents/monorepo-manager/pkgs/mono/config.nims' [Conf]
..................................................................................................
~/Documents/monorepo-manager/pkgs/mono/test.nim(5, 7) Error: 'error' can only be used in compile-time context

Simply removing the argparse import results in a successful compilation.

"Expected 1 args but only found 0" is too vague

this code shows 2 behaviors that I hope might be improved:

  1. If an option (--info below) is specified multiple times by the user, no warning is given and only the last is used. I would prefer this to give an error or at least a warning
  2. If parse() is called without arguments, then it gives an exception that's not helpful to the user.
    Is there something I can do to make outputting the help as a default? I always check if args.len == 0 and if so I set args = @["--help"].
    thanks for the great library. I'm using it in all of my projects now.
import argparse

var p = newParser("example"):
  option("--info")
  arg("arg")

var opts = p.parse(@["--info", "asdf", "--info", "asdf", "arg"])
echo opts

discard p.parse()

Request: forward facing object/variable with components defined in newParser()

I am trying to implement something similar to ArgDoc, but unfortunately I am pretty novice and macros and templates still baffle me. I wanted to get an object/sequence/something that contained all of the components after I defined them in the newParser template.

I see you have the Builder object and the BuilderStack, and I tried playing around with those, without success.

Any help/suggestions greatly appreciated!

Passing an option value without `=` breaks parsing multiple arguments

import argparse

when isMainModule:
  var p = newParser:
    option("-n", "--number", default=some("0"))
    arg("inputA", nargs = 1)
    arg("inputB", nargs = 1)

  try:
    let opts = p.parse(@["-n 2", "A", "B"])
  except UsageError:
    stderr.writeLine getCurrentExceptionMsg()
    quit(1)

Output: Unknown argument(s): B
Changing "-n 2" to "-n=2" works as expected.

This passes, which is unexpected (and, IMO, broken):

import argparse

when isMainModule:
  var p = newParser:
    option("-n", "--number", default=some("0"))
    arg("inputA", nargs = 1)
    arg("inputB", nargs = 1)
  let opts = p.parse(@["-n 2", "A"])
  doAssert opts.number == "0"
  doAssert opts.inputA == "-n 2"
  doAssert opts.inputB == "A"

It looks like argparse can't parse a value for an option without =. The docs are not clear on the rules, the only mention of allowed format is in the table on the doc page:

option(...) option with argument (e.g. --output foo)

Which means passing whitespace delimited option values should work.

help option is not set?

Consider the following code:

let p = newParser("My Program"):
        option("-o", "--output", help="Output to file")
let opts = p.parse(commandLineParams())
echo opts.help

If I call the application with the help argument, I'd expect to print "true". Unfortunately in both cases it prints "false".
Is this the expected behaviour?

allow specifying required=true for `arg`

this would be nice to avoid checking e.g.

if opts.myargs == "":
    quit p.help & "\nmyarg is required"

I guess this could also be via nargs=1, but that does not currently give an error if no arguments are given.

Allow me to get subcommand options

I'm imagining this design with Options:

var p = newParser:
  command "foo":
    flag("-a")
  command "bar":
    flag("-b")

var opts = p.parse(@["foo", "-a"])
assert opts.argparse_command == "foo"
assert opts.foo_opts.get().a == true
assert opts.bar_opts.isNone

# or maybe with an 'argparse_' prefix, though I don't like all the extra typing:
assert opts.argparse_foo_opts.get().a == true
assert opts.argparse_bar_opts.isNone

ENH: allow repeated options.

thanks for the library. it looks close to what I need and I'm trying to get it going in one of my projects.
however, I'd like to be able to do something like:

    option("-f", "--field", help="field(s) to use for value", nargs=-1)

and then on the command-line, the user could specify

  -f abc -f def -f xyz

and the parsed result would be @["abc", "def", "xyz"]

is something like this possible? I need this independently from arg because I have mutliple options that allow variable number of arguments.

Automatic identification of the application binary name (feature request)

Automatic identification of the application binary name (besides the manual name specification) is a standard feature in all arguments parsers but is not supported by the nim-argparse yet.

Standard approaches to identify the name of the executing binary in Nim do not work with nim-argparse having the run-time execution:

let appname = getAppFilename().extractFilename()  # Full canonical filename
let binname = paramStr(0)  # Binary name

where the argument parser is constructed in the compile-time...

I also tried to change the parser construction from

mkParser(name, true, "", proc() = content)

to

mkParser(when name.len < 2 or name[0] != '$': name else: getEnv(name, # or substr(name, 1),
  default="<" & name & ">"), ...)

assuming to interpret $0 as the app binary name from the environment like in bash since getEnv() works in the compile time but this environment variable is not defined for the nimble build...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.