typed-argument-parser icon indicating copy to clipboard operation
typed-argument-parser copied to clipboard

`parse_args` should return the chosen sub parser object

Open JasonGilholme opened this issue 4 years ago • 4 comments
trafficstars

Hi,

I'm using sub parsers and I assumed that the Tap for the chosen sub parser would be returned from parse_args() however the parent parser is actually returned. The motivation for having the sub parser returned is as follows:

  • allow additional functionality to be loaded on to the parser
  • get code completion for the sub parser as you do for the parent parser
  • determine which sub parser was chosen in a manner that typing can understand.

For example:


class SubParserA(Tap):

    foo: str

    def do_foo(self):
        # Do something with self.foo here


class SubParserB(Tap)

    bar: str

    def do_bar(self):
        # Do something with self.bar here


class MainParser(Tap):

    def configure(self) -> None:
        self.add_subparsers()
        self.add_subparser('a', SubParserA)
        self.add_subparser('b', SubParserB)


if __name__ == '__main__':
    main_parser = MainParser()
    args = main_parser.parse_args()

    if isinstance(args, SubParserA):
        args.do_foo()
    elif isinstance(args, SubParserB):
        args.do_bar()

Would be great to hear your thoughts!

Cheers Jase

JasonGilholme avatar Nov 08 '21 02:11 JasonGilholme

Hi @JasonGilholme,

Thank you for raising this issue! We agree that the current behavior is not ideal. We've already put some thought into this problem https://github.com/swansonk14/typed-argument-parser/issues/17#issuecomment-809587061, but we're still thinking about it.

For future us and perhaps others, we'll leave some runnable code that breaks (heavily inspired by your code) when you run python file.py a --foo biz:

from tap import Tap

class SubParserA(Tap):
    foo: str

    def do_foo(self):
        pass

class SubParserB(Tap):
    bar: str

    def do_bar(self):
        pass

class MainParser(Tap):

    def configure(self) -> None:
        self.add_subparsers()
        self.add_subparser('a', SubParserA)
        self.add_subparser('b', SubParserB)


if __name__ == '__main__':
    main_parser = MainParser()
    args = main_parser.parse_args()

    args.do_foo()

Best, Jesse and Kyle

martinjm97 avatar Dec 30 '21 02:12 martinjm97

I would like to second this. With the current implementation I am not sure how this is supposed to work, but in the example you provide, the code to access args.foo or args.bar gives a type exception (VS Code/pylance). Which makes sense since they are defined in separate classes.

What I expected:

from tap import Tap

class MainParser(Tap):
    shared: str

    def configure(self) -> None:
        self.add_subparser('a', SubParserA)
        self.add_subparser('b', SubParserB)

class SubParserA(MainParser):
    foo: str

class SubParserB(MainParser):
    bar: str

if __name__ == '__main__':
    args = MainParser().parse_args()
    if isinstance(args, SubParserA):
        print(args.shared)
        print(args.foo)

That code does not show any errors in the editor, but when run goes into an infinite loop which seems to involve _get_class_variables and _get_from_self_and_super. And without the subclasses, the "isinstance" part will never be true. Is there a trick for that?

As an aside, it would be nice to allow "None" as the subparse class, for subparsers without additional arguments. I created a NoArgs object instead, so maybe that's good enough, but maybe include as an example?

pdc1 avatar Dec 31 '21 18:12 pdc1

Hi all,

We’re working on sketching a plan for a Tap version 2 release. We have a sketch of the solution to a number of issues including this one. This includes a breaking change to the treatment of subparsers and a different way that we treat comments to support argument groups. We’re excited to start the implementation and would love feedback and recommendations from everyone. We’re so appreciative of all of the wonderful pull requests, issues, and ideas from all of you!

Best, Kyle and Jesse

swansonk14 avatar Feb 06 '22 02:02 swansonk14

See my comments at https://github.com/swansonk14/typed-argument-parser/issues/69#issuecomment-1036417593. Thanks!

pdc1 avatar Feb 11 '22 17:02 pdc1