diff --git a/arger/parser/classes.py b/arger/parser/classes.py index 9ca3a64..5b005e1 100644 --- a/arger/parser/classes.py +++ b/arger/parser/classes.py @@ -1,7 +1,9 @@ import argparse from enum import Enum from inspect import isclass -from typing import Any, List, Optional, Tuple +from typing import Any, List, Tuple + +from arger.parser.utils import generate_flags from ..types import UNDEFINED from ..typing_utils import match_types @@ -21,14 +23,7 @@ def get_action( class Option: def __init__( - self, - flags: Tuple[str, ...] = (), - type_: Any = UNDEFINED, - default: Any = UNDEFINED, - help_: str = "", - metavar: Optional[str] = None, - required=False, - **kwargs, + self, flags: List[str], default: Any = UNDEFINED, **kwargs, ): """Represent optional arguments to the command. @@ -69,6 +64,7 @@ def __init__( self.flags = flags + type_ = kwargs.pop('type', UNDEFINED) if default is not UNDEFINED: kwargs["default"] = default @@ -82,20 +78,20 @@ def __init__( elif (type_ is not UNDEFINED) and type_ != bool: kwargs.setdefault("type", type_) - kwargs.setdefault('help', help_) - kwargs.setdefault('metavar', metavar) - kwargs.setdefault('required', required) self.kwargs = kwargs def add(self, parser: argparse.ArgumentParser): return parser.add_argument(*self.flags, **self.kwargs) + def __repr__(self): + return f'{self.__class__.__name__}: {self.flags}, {repr(self.kwargs)}' + + def set_flags(self, option_generator): + hlp = self.kwargs.pop('help').split() + # generate flags + self.flags = generate_flags(self.flags[0], hlp, option_generator) + self.kwargs['help'] = " ".join(hlp) + class Argument(Option): """Represent positional argument that are required.""" - - def __init__( - self, **kwargs, - ): - """See Option.__init__'s doc for more info.""" - super().__init__(required=True, **kwargs) diff --git a/arger/parser/parser.py b/arger/parser/parser.py index b1faf65..db82436 100644 --- a/arger/parser/parser.py +++ b/arger/parser/parser.py @@ -6,7 +6,7 @@ from ..types import UNDEFINED from .classes import Argument, Option -from .utils import generate_flags, generate_options +from .utils import generate_options def prepare_arguments(func, param_docs,) -> Dict[str, Option]: @@ -42,26 +42,26 @@ def prepare_arguments(func, param_docs,) -> Dict[str, Option]: option_generator = generate_options() next(option_generator) - arguments: Dict[str, Option] = OrderedDict() - for param in positional_params: - arguments[param] = Argument( - help_=param_docs.get(param, ""), + def get_args(param): + return dict( flags=[param], - dest=param, - type_=annotations.get(param, UNDEFINED), + help=param_docs.get(param, ""), + type=annotations.get(param, UNDEFINED), ) + arguments: Dict[str, Option] = OrderedDict() + for param in positional_params: + arguments[param] = Argument(**get_args(param)) + for param, default in kw_params.items(): - hlp = param_docs.get(param, "") - flags = generate_flags(param, hlp, option_generator) - hlp = " ".join(hlp) - arguments[param] = Option( - help_=hlp, - flags=flags, - dest=param, - type_=annotations.get(param, UNDEFINED), - default=default, - ) + if isinstance(default, Argument): + default.flags = [param] + elif isinstance(default, Option): + default.set_flags(option_generator) + else: + default = Option(dest=param, default=default, **get_args(param)) + default.set_flags(option_generator) + arguments[param] = default return arguments diff --git a/arger/parser/utils.py b/arger/parser/utils.py index 1efbcc2..fb91c9a 100644 --- a/arger/parser/utils.py +++ b/arger/parser/utils.py @@ -1,4 +1,4 @@ -from typing import Set +from typing import List, Set def generate_options(): @@ -25,7 +25,7 @@ def generate_options(): def generate_flags( - param, param_doc, option_generator, + param: str, param_doc: List[str], option_generator, ): names = [] diff --git a/tests/test_fn_parser.py b/tests/test_fn_parser.py index ef84464..e0e7948 100644 --- a/tests/test_fn_parser.py +++ b/tests/test_fn_parser.py @@ -1,4 +1,7 @@ +from collections import OrderedDict + from arger.parser import opterate +from arger.parser.classes import Argument from .utils import _reprint @@ -15,15 +18,18 @@ def main(param1: int, param2: str, kw1=None, kw2=False): def test_opterate(): doc, args = opterate(func=main) assert doc == "Example function with types documented in the docstring." - assert args == [ - (['param1'], {'action': 'store', 'help': 'The first parameter.', 'type': int}), - (['param2'], {'action': 'store', 'help': 'The second parameter.', 'type': str}), - ( - ['-k', '--kw1'], - {'action': 'store', 'default': None, 'dest': 'kw1', 'help': ''}, - ), - ( - ['-w', '--kw2'], - {'action': 'store_true', 'default': False, 'dest': 'kw2', 'help': '',}, - ), + assert list(args) == ['param1', 'param2', 'kw1', 'kw2'] + + assert [v.flags for v in args.values()] == [ + ['param1'], + ['param2'], + ['-k', '--kw1'], + ['-w', '--kw2'], + ] + + assert [v.kwargs for v in args.values()] == [ + {'action': 'store', 'help': 'The first parameter.', 'type': int,}, + {'action': 'store', 'help': 'The second parameter.', 'type': str,}, + {'action': 'store', 'default': None, 'dest': 'kw1', 'help': '',}, + {'action': 'store_true', 'default': False, 'dest': 'kw2', 'help': '',}, ]