From b5127919657f367d38a7530e78a23d273f05e1b4 Mon Sep 17 00:00:00 2001 From: hjoaquim Date: Mon, 6 May 2024 12:35:02 +0100 Subject: [PATCH 1/3] remove about message --- cli/openbb_cli/controllers/base_controller.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cli/openbb_cli/controllers/base_controller.py b/cli/openbb_cli/controllers/base_controller.py index a3d8b20aa162..1f40fc61b0a4 100644 --- a/cli/openbb_cli/controllers/base_controller.py +++ b/cli/openbb_cli/controllers/base_controller.py @@ -876,11 +876,6 @@ def parse_known_args_and_warn( if "--help" in other_args or "-h" in other_args: txt_help = parser.format_help() + "\n" - if parser.prog != "about": - txt_help += ( - f"For more information and examples, use 'about {parser.prog}' " - f"to access the related guide.\n" - ) session.console.print(f"[help]{txt_help}[/help]") return None From c995db7ec858c5926ed75ece740387a2cf56d9d1 Mon Sep 17 00:00:00 2001 From: hjoaquim Date: Mon, 6 May 2024 12:36:22 +0100 Subject: [PATCH 2/3] handle repeated arguments --- .../argparse_translator.py | 72 ++++++++++++++----- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/cli/openbb_cli/argparse_translator/argparse_translator.py b/cli/openbb_cli/argparse_translator/argparse_translator.py index 45fa4ce5d6b7..c8fa5d257172 100644 --- a/cli/openbb_cli/argparse_translator/argparse_translator.py +++ b/cli/openbb_cli/argparse_translator/argparse_translator.py @@ -21,6 +21,8 @@ from pydantic import BaseModel, model_validator from typing_extensions import Annotated +# pylint: disable=protected-access + SEP = "__" @@ -200,7 +202,7 @@ def __init__( self.func = func self.signature = inspect.signature(func) self.type_hints = get_type_hints(func) - self.provider_parameters = [] + self.provider_parameters: List[str] = [] self._parser = argparse.ArgumentParser( prog=func.__name__, @@ -217,23 +219,59 @@ def __init__( for group in custom_argument_groups: argparse_group = self._parser.add_argument_group(group.name) for argument in group.arguments: - kwargs = argument.model_dump(exclude={"name"}, exclude_none=True) - - # If the argument is already in use, we can't repeat it - if f"--{argument.name}" not in self._parser_arguments(): - argparse_group.add_argument(f"--{argument.name}", **kwargs) - self.provider_parameters.append(argument.name) - - def _parser_arguments(self) -> List[str]: - """Get all the arguments from all groups currently defined on the parser.""" - arguments_in_use: List[str] = [] - - # pylint: disable=protected-access - for action_group in self._parser._action_groups: - for action in action_group._group_actions: - arguments_in_use.extend(action.option_strings) + self._handle_argument_in_groups(argument, argparse_group) + + def _handle_argument_in_groups(self, argument, group): + """Handle the argument and add it to the parser.""" + + def _in_optional_arguments(arg): + for action_group in self._parser._action_groups: + if action_group.title == "optional arguments": + for action in action_group._group_actions: + opts = action.option_strings + if (opts and opts[0] == arg) or action.dest == arg: + return True + return False + + def _remove_argument(arg): + # remove the argument from the parser + for action in self._parser._actions: + opts = action.option_strings + if (opts and opts[0] == arg) or action.dest == arg: + self._parser._remove_action(action) + break - return arguments_in_use + # remove from all groups + for action_group in self._parser._action_groups: + for action in action_group._group_actions: + opts = action.option_strings + if (opts and opts[0] == arg) or action.dest == arg: + action_group._group_actions.remove(action) + + # remove from _action_groups dict + self._parser._option_string_actions.pop(f"--{arg}", None) + + # remove from the provider_parameters + if arg in self.provider_parameters: + self.provider_parameters.remove(arg) + + # check if the argument is already in use, if not, add it + if f"--{argument.name}" not in self._parser._option_string_actions: + kwargs = argument.model_dump(exclude={"name"}, exclude_none=True) + group.add_argument(f"--{argument.name}", **kwargs) + self.provider_parameters.append(argument.name) + + else: + # check if the argument is in the optional arguments + if _in_optional_arguments(argument.name): + return + # if the argument is in use, remove it and add it to the optional arguments group + _remove_argument(argument.name) + + self._parser.add_argument( + f"--{argument.name}", + **argument.model_dump(exclude={"name"}, exclude_none=True), + ) @property def parser(self) -> argparse.ArgumentParser: From 645eb89a371c0e4fd38d5cfc50621022c568bab2 Mon Sep 17 00:00:00 2001 From: hjoaquim Date: Mon, 6 May 2024 14:11:30 +0100 Subject: [PATCH 3/3] accomodate all the choices from different providers --- .../argparse_translator.py | 57 +++++++++++++++---- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/cli/openbb_cli/argparse_translator/argparse_translator.py b/cli/openbb_cli/argparse_translator/argparse_translator.py index c8fa5d257172..bf5917207d50 100644 --- a/cli/openbb_cli/argparse_translator/argparse_translator.py +++ b/cli/openbb_cli/argparse_translator/argparse_translator.py @@ -1,5 +1,6 @@ import argparse import inspect +import re from copy import deepcopy from enum import Enum from typing import ( @@ -233,7 +234,9 @@ def _in_optional_arguments(arg): return True return False - def _remove_argument(arg): + def _remove_argument(arg) -> List[Optional[str]]: + groups_w_arg = [] + # remove the argument from the parser for action in self._parser._actions: opts = action.option_strings @@ -247,13 +250,29 @@ def _remove_argument(arg): opts = action.option_strings if (opts and opts[0] == arg) or action.dest == arg: action_group._group_actions.remove(action) + groups_w_arg.append(action_group.title) # remove from _action_groups dict self._parser._option_string_actions.pop(f"--{arg}", None) - # remove from the provider_parameters - if arg in self.provider_parameters: - self.provider_parameters.remove(arg) + return groups_w_arg + + def _get_arg_choices(arg) -> Tuple: + for action in self._parser._actions: + opts = action.option_strings + if (opts and opts[0] == arg) or action.dest == arg: + return tuple(action.choices or ()) + return () + + def _update_providers( + input_string: str, new_provider: List[Optional[str]] + ) -> str: + pattern = r"\(provider:\s*(.*?)\)" + providers = re.findall(pattern, input_string) + providers.extend(new_provider) + # remove pattern from help and add with new providers + input_string = re.sub(pattern, "", input_string).strip() + return f"{input_string} (provider: {', '.join(providers)})" # check if the argument is already in use, if not, add it if f"--{argument.name}" not in self._parser._option_string_actions: @@ -262,16 +281,34 @@ def _remove_argument(arg): self.provider_parameters.append(argument.name) else: + kwargs = argument.model_dump(exclude={"name"}, exclude_none=True) + model_choices = kwargs.get("choices", ()) or () + # extend choices + choices = tuple(set(_get_arg_choices(argument.name) + model_choices)) + # check if the argument is in the optional arguments if _in_optional_arguments(argument.name): + for action in self._parser._actions: + if action.dest == argument.name: + # update choices + action.choices = choices + # update help + action.help = _update_providers( + action.help or "", [group.title] + ) return - # if the argument is in use, remove it and add it to the optional arguments group - _remove_argument(argument.name) - self._parser.add_argument( - f"--{argument.name}", - **argument.model_dump(exclude={"name"}, exclude_none=True), - ) + # if the argument is in use, remove it from all groups + # and return the groups that had the argument + groups_w_arg = _remove_argument(argument.name) + groups_w_arg.append(group.title) # add current group + + # add it to the optional arguments group instead + if choices: + kwargs["choices"] = choices # update choices + # add provider info to the help + kwargs["help"] = _update_providers(argument.help or "", groups_w_arg) + self._parser.add_argument(f"--{argument.name}", **kwargs) @property def parser(self) -> argparse.ArgumentParser: