Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rendre le output de "--help" moins laid #34

Open
lebrice opened this issue Mar 8, 2023 · 3 comments · May be fixed by #41
Open

Rendre le output de "--help" moins laid #34

lebrice opened this issue Mar 8, 2023 · 3 comments · May be fixed by #41
Assignees

Comments

@lebrice
Copy link
Contributor

lebrice commented Mar 8, 2023

Je me suis donné la tâche de rendre le help text plus simple, parce que @abergeron trouve ça "laitte en criss".

La solution va surement ressembler à ceci:

import argparse
from typing_extensions import Literal
from simple_parsing import ArgumentParser
from dataclasses import dataclass


@dataclass
class GlobalArgs:
    """Global args."""

    verbose: bool = False
    debug: bool = False


@dataclass
class Db:
    """Db help"""

    name: str
    bar: int = 0  # bar help

    def execute(self):
        print(f"Executing {self}")


@dataclass
class Acquire:
    """Acquire help"""

    job_name: str
    baz: Literal["X", "Y", "Z"] = "X"  # baz help

    def execute(self):
        print(f"Executing {self}")


def main():
    parser = ArgumentParser(prog="test")
    parser.add_arguments(GlobalArgs, dest="global_args")

    command_subparsers = parser.add_subparsers(
        dest="command_name",
        title="Command title",
        description="Description",
        required=True,
    )

    db_parser = command_subparsers.add_parser("db", help="DB help")
    db_parser.add_arguments(Db, dest="command")

    acquire_parser = command_subparsers.add_parser("acquire", help="Acquire help")
    acquire_parser.add_arguments(Acquire, dest="command")

    args = parser.parse_args()

    global_args: GlobalArgs = args.global_args
    chosen_command_name: str = args.command_name

    command: Db | Acquire = args.command
    command.execute()


if __name__ == "__main__":
    main()

Help output:

usage: test [-h] [--verbose bool] [--debug bool] {db,acquire} ...

options:
  -h, --help            show this help message and exit

Command title:
  Description

  {db,acquire}
    db                  DB help
    acquire             Acquire help

GlobalArgs ['global_args']:
  Global args.

  --verbose bool, --noverbose bool
                        (default: False)
  --debug bool, --nodebug bool
                        (default: False)                    
@lebrice lebrice self-assigned this Mar 8, 2023
lebrice added a commit that referenced this issue Mar 14, 2023
Fixes #34

Signed-off-by: Fabrice Normandin <normandf@mila.quebec>
@lebrice lebrice linked a pull request Mar 14, 2023 that will close this issue
lebrice added a commit that referenced this issue Mar 14, 2023
Fixes #34

Signed-off-by: Fabrice Normandin <normandf@mila.quebec>
lebrice added a commit that referenced this issue Mar 14, 2023
Fixes #34

Signed-off-by: Fabrice Normandin <normandf@mila.quebec>
lebrice added a commit that referenced this issue Mar 14, 2023
Fixes #34

Signed-off-by: Fabrice Normandin <normandf@mila.quebec>
lebrice added a commit that referenced this issue Mar 14, 2023
Fixes #34

Signed-off-by: Fabrice Normandin <normandf@mila.quebec>
lebrice added a commit that referenced this issue Mar 14, 2023
Fixes #34

Signed-off-by: Fabrice Normandin <normandf@mila.quebec>
@Delaunay
Copy link
Collaborator

Pour reference sarc --help ressemble a

sarc --help
usage: sarc [-h] [-v] {acquire,db} ...

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

CLI ['command']:
  CLI(command: 'Union[Acquire, Db]', verbose: 'int' = 0)

  -v, --verbose  logging levels of information about the process (-v: INFO. -vv: DEBUG) (default: 0)

command:
  {acquire,db}

@Delaunay
Copy link
Collaborator

Would be nice to see more depth in the argument tree

import argparse
from typing import Union
from typing_extensions import Literal
from simple_parsing import ArgumentParser
from dataclasses import dataclass
from simple_parsing import subparsers
from pathlib import Path
from sarc.common.format import HelpAction


@dataclass
class GlobalArgs:
    """Global args."""

    verbose: bool = False
    debug: bool = False


@dataclass
class Db:
    """Db help"""

    name: str
    bar: int = 0  # bar help
    

    def execute(self):
        print(f"Executing {self}")


@dataclass
class Acquire:
    """Acquire help"""
    
    
    @dataclass
    class Allocations:
        file: Path
    
    @dataclass
    class Jobs:
        file: Path
    
    @dataclass
    class Storages:
        file: Path

    command: Union[Allocations, Jobs, Storages] = subparsers(
        {
            "allocations": Allocations,
            "jobs": Jobs,
            "storages": Storages,
        }
    )
    
    def execute(self):
        print(f"Executing {self}")


def main():
    parser = ArgumentParser(prog="test", add_help=False)
    parser.add_argument(
        "-h", "--help", action=HelpAction, help="show this help message and exit"
    )
    
    parser.add_arguments(GlobalArgs, dest="global_args")

    command_subparsers = parser.add_subparsers(
        dest="command_name",
        title="Command title",
        description="Description",
        required=True,
    )

    db_parser = command_subparsers.add_parser("db", help="DB help")
    db_parser.add_arguments(Db, dest="command")

    acquire_parser = command_subparsers.add_parser("acquire", help="Acquire help")
    acquire_parser.add_arguments(Acquire, dest="command")

    args = parser.parse_args()

    global_args: GlobalArgs = args.global_args
    chosen_command_name: str = args.command_name

    command: Db | Acquire = args.command
    command.execute()


if __name__ == "__main__":
    main()
python args.py --help
 help                                     HelpAction
 db                                       _SubParsersAction
   help                                   _HelpAction
 acquire                                  _SubParsersAction
   help                                   _HelpAction
 global_args.verbose                      BooleanOptionalAction
 global_args.debug                        BooleanOptionalAction

does not show acquire allocations etc ....

@Delaunay
Copy link
Collaborator

Delaunay commented Jul 29, 2023

I think something like would look cleaner. but I am not sure how it would fit within simple parsing

from argparse import ArgumentParser
from dataclasses import dataclass, field, fields
from typing import Optional

def subparser(datacls, dest=None):
    return field(metadata={"type": "subparser", "datacls": datacls, "dest": dest}, default=None)
    

@dataclass
class Allocations:
    file: str


@dataclass
class Jobs:
    file: str


@dataclass
class Storages:
    file: str


@dataclass
class Acquire:
    allocations: Optional[Allocations] = subparser(Allocations, 'subcmd')
    jobs: Optional[Jobs] = subparser(Jobs, 'subcmd')
    storages: Optional[Storages] = subparser(Storages, 'subcmd')
    

@dataclass
class CommandLineInterface:
    acquire: Acquire = subparser(Acquire, 'cmd')


def add_arguments(parser: ArgumentParser, dataclass):
    subparsers = dict()
    
    for field in fields(dataclass):
        # print(field)
        
        fieldtype = field.metadata.get('type')
        
        if fieldtype == 'subparser':
            dest = field.metadata.get('dest')
            dtcls = field.metadata.get('datacls')
            
            # Group subparser by destination
            subparser = subparsers.get(dest)
            if subparser is None :
                subparser = parser.add_subparsers(dest=dest)
                subparsers[dest] = subparser
                
            cmdparser = subparser.add_parser(field.name)
            add_arguments(cmdparser, dtcls)
        else:
            parser.add_argument(field.name)
        

from sarc.common.format import HelpAction
    
parser = ArgumentParser(add_help=False)
parser.add_argument(
    "-h", "--help", action=HelpAction, help="show this help message and exit"
)
add_arguments(parser, CommandLineInterface)

args = parser.parse_args()

it prints, so it does materialize the full parser, opening more options for formatting

 acquire                                  _SubParsersAction
   allocations                            _SubParsersAction
     file                                 _StoreAction
     help                                 _HelpAction
   jobs                                   _SubParsersAction
     file                                 _StoreAction
     help                                 _HelpAction
   storages                               _SubParsersAction
     file                                 _StoreAction
     help                                 _HelpAction
   help                                   _HelpAction
 help                                     HelpAction

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants