kotlin-argparser icon indicating copy to clipboard operation
kotlin-argparser copied to clipboard

Interest in better support for sub parsers

Open DarrienG opened this issue 6 years ago • 2 comments

Kotlin version 1.2.60-release-76 (JRE 10.0.2+13)
com.xenomachina:kotlin-argparser:2.0.7

I (unfortunately) write Python almost every day at work, and we use Argparse there most of the time.

Argparse has wonderful support for subparsers, but it seems fairly tedious to do with this library.

Say I'm writing a cli for a program like this:

$ timetracker-client -h
usage: [-h] [-l LOGIN] [-r REGISTER] [--verbose] [--quiet] [--status]
       [--add-task ADD_TASK]...

optional arguments:
  -h, --help             show this help message and exit

  -l LOGIN,              Initialize client with user info and log in. User
  --login LOGIN          info passed in as properties file with format:
                         email=<EMAIL> password=<PASSWORD>

  --add-task ADD_TASK,   Add a task.
  -a ADD_TASK

And I want a separate parser for --add-task. It will have its own positional arguments and its own help menu. Something like this:

$ timetracker-client --add-task --help
usage: [-h] TASK CATEGORY START_TIME END_TIME [PROPERTIES]...

optional arguments:
  -h, --help   show this help message and exit


positional arguments:
  TASK         Name of task being stored

  CATEGORY     Category of task to store

  START_TIME   Start time of a task in the format yyyy/mm/dd-hh:mm

  END_TIME     End time of a task in the format yyyy/mm/dd-hh:mm

  PROPERTIES   Extra properties desired to be saved in the format:
               prop1:Property prop2:property

Doesn't seem too unreasonable I think.

But from going through the docs, it doesn't appear this functionality is built in. To add this functionality on my own, I end up doing a bunch of array splicing, and then sending that task to the parser I want to run.

It's not particularly nice, but I'm getting it done with this code: https://gitlab.com/time-tracker-utils/TerminalTimetrackerClient/blob/master/src/main/kotlin/Client.kt#L9 I'm aware I could use a positional list for the -a option, but that surrenders more control.

It would be very nice if I could do something like this:

val addTask: TaskParser by parser.subparser("--add-task", "-a",
        help = "Add a task.\n")

Where TaskParser is something like this:

class TaskParser(parser: ArgParser) {
    val task: String by parser.positional("TASK",
            help = "Name of task being stored")

    val category: String by parser.positional("CATEGORY",
            help = "Category of task to store")
// ABBREVIATED
}

But this does not seem to be very easy.

I'm currently using this library for a personal project here: https://gitlab.com/time-tracker-utils/TerminalTimetrackerClient/tree/master and it's been great so far, but this was a large gripe that cost me a few hours today trying to understand a good way of adding subparsers.

In the end, I couldn't find one.

Please advise - and if it doesn't exist, I might make my own PR in the coming weeks.

DarrienG avatar Sep 09 '18 00:09 DarrienG

If need support for subcommands, you can try other libraries like clikt

johntoid avatar Oct 21 '18 17:10 johntoid

I was able to do it by having 2 classes and composing them.

data class Core(val parser: ArgParser) {
    val email: String by parser.storing("email")
}
data class Extended(val argParser: ArgParser) {
    val core: Core = Core(argParser)
    val name by argParser.storing("name")
}

but this might not cover all the use cases you are looking for.

wakingrufus avatar Apr 26 '19 15:04 wakingrufus