From 62551d20d1c5a524cd07dfdd596e9ba05b335548 Mon Sep 17 00:00:00 2001 From: hjoaquim Date: Fri, 28 Jul 2023 11:24:40 +0100 Subject: [PATCH] adjustments to the translation --- .../argparse_class_processor.py | 18 ++- argparse_translator/argparse_translator.py | 21 ++- openbb_terminal/core/completer/choices.py | 16 +-- openbb_terminal/parent_classes.py | 10 +- openbb_terminal/stocks/stocks_controller.py | 133 ++---------------- 5 files changed, 53 insertions(+), 145 deletions(-) diff --git a/argparse_translator/argparse_class_processor.py b/argparse_translator/argparse_class_processor.py index 1b9025b8e79..8c5eea303e1 100644 --- a/argparse_translator/argparse_class_processor.py +++ b/argparse_translator/argparse_class_processor.py @@ -1,5 +1,5 @@ import inspect -from typing import Type +from typing import Type, Dict from argparse_translator.argparse_translator import ArgparseTranslator @@ -9,7 +9,7 @@ class ArgparseClassProcessor: Process a target class to create ArgparseTranslators for its methods. """ - def __init__(self, target_class: Type, menu_designation: str): + def __init__(self, target_class: Type, menu_designation: str, add_help: bool): """ Initialize the ArgparseClassProcessor. @@ -20,9 +20,12 @@ class ArgparseClassProcessor: menu_designation : str The designation for the menu level associated with the target class. """ - self._target_class = target_class - self._menu_designation = menu_designation - self._translators = {self._menu_designation: {}} + self._target_class: Type = target_class + self._menu_designation: str = menu_designation + self._add_help: bool = add_help + self._translators: Dict[str, Dict[str, ArgparseTranslator]] = { + self._menu_designation: {} + } self._process_methods() @@ -33,7 +36,10 @@ class ArgparseClassProcessor: for name, method in inspect.getmembers(self._target_class, inspect.ismethod): if name.startswith("__"): continue - self._translators[self._menu_designation][name] = ArgparseTranslator(method) + + self._translators[self._menu_designation][name] = ArgparseTranslator( + func=method, add_help=self._add_help + ) def get_translator(self, menu: str, command: str) -> ArgparseTranslator: """ diff --git a/argparse_translator/argparse_translator.py b/argparse_translator/argparse_translator.py index 708f24ae58d..4d82cf92d2b 100644 --- a/argparse_translator/argparse_translator.py +++ b/argparse_translator/argparse_translator.py @@ -15,6 +15,7 @@ from typing import ( get_origin, get_type_hints, ) +from copy import deepcopy from pydantic import BaseModel from typing_extensions import Annotated @@ -45,7 +46,8 @@ class ArgparseTranslator: self.signature = inspect.signature(func) self.type_hints = get_type_hints(func) - self.parser = argparse.ArgumentParser( + self._parser = argparse.ArgumentParser( + prog=func.__name__, description=func.__doc__, formatter_class=argparse.RawTextHelpFormatter, add_help=add_help, @@ -53,6 +55,10 @@ class ArgparseTranslator: self._generate_argparse_arguments(self.signature.parameters) + @property + def parser(self) -> argparse.ArgumentParser: + return deepcopy(self._parser) + @staticmethod def _param_is_default(param: inspect.Parameter) -> bool: return param.default != inspect.Parameter.empty @@ -194,7 +200,7 @@ class ArgparseTranslator: kwargs.pop("type") kwargs.pop("nargs") - self.parser.add_argument( + self._parser.add_argument( f"--{param.name}", **kwargs, ) @@ -235,7 +241,14 @@ class ArgparseTranslator: ) -> Any: kwargs = self._unflatten_args(vars(parsed_args)) kwargs = self._update_with_custom_types(kwargs) - kwargs.pop("help", None) + + # remove kwargs that doesn't match the signature + kwargs = { + key: value + for key, value in kwargs.items() + if key in self.signature.parameters + } + return self.func(**kwargs) def parse_args_and_execute(self) -> Any: @@ -245,7 +258,7 @@ class ArgparseTranslator: Returns: Any: The return value of the original function. """ - parsed_args = self.parser.parse_args() + parsed_args = self._parser.parse_args() return self.execute_func(parsed_args) def translate(self) -> Callable: diff --git a/openbb_terminal/core/completer/choices.py b/openbb_terminal/core/completer/choices.py index 0268a0693aa..ac2d598140f 100644 --- a/openbb_terminal/core/completer/choices.py +++ b/openbb_terminal/core/completer/choices.py @@ -39,13 +39,9 @@ def __mock_parse_known_args_and_warn( _ = other_args - # only add the help argument if it's not already there - usage = StringIO() - parser.print_usage(file=usage) - if "[-h]" not in usage.getvalue(): - parser.add_argument( - "-h", "--help", action="store_true", help="show this help message" - ) + parser.add_argument( + "-h", "--help", action="store_true", help="show this help message" + ) if export_allowed > 0: choices_export = [] @@ -271,8 +267,10 @@ def _get_argument_parser( for patched_function in patched_function_list: call_count += patched_function.call_count if patched_function.call_count == 1: - args = patched_function.call_args.args - argument_parser = args[0] + args, kwargs = patched_function.call_args + argument_parser = ( + kwargs["parser"] if kwargs.get("parser", None) else args[0] + ) if call_count != 1: raise AssertionError( diff --git a/openbb_terminal/parent_classes.py b/openbb_terminal/parent_classes.py index 0451e7b98e3..e460f604863 100644 --- a/openbb_terminal/parent_classes.py +++ b/openbb_terminal/parent_classes.py @@ -1124,13 +1124,9 @@ class BaseController(metaclass=ABCMeta): Namespace with parsed arguments """ - # only add the help argument if it's not already there - usage = StringIO() - parser.print_usage(file=usage) - if "[-h]" not in usage.getvalue(): - parser.add_argument( - "-h", "--help", action="store_true", help="show this help message" - ) + parser.add_argument( + "-h", "--help", action="store_true", help="show this help message" + ) if config_terminal.HOLD: parser.add_argument( diff --git a/openbb_terminal/stocks/stocks_controller.py b/openbb_terminal/stocks/stocks_controller.py index 21c602f1df9..3af0a779250 100644 --- a/openbb_terminal/stocks/stocks_controller.py +++ b/openbb_terminal/stocks/stocks_controller.py @@ -37,7 +37,9 @@ from openbb_terminal.terminal_helper import suppress_stdout logger = logging.getLogger(__name__) -stocks_translations = ArgparseClassProcessor(obb.stocks, "stocks") +stocks_translations = ArgparseClassProcessor( + target_class=obb.stocks, menu_designation="stocks", add_help=False +) class StocksController(StockBaseController): @@ -156,7 +158,6 @@ class StocksController(StockBaseController): def call_load(self, other_args: List[str]): """Process load command.""" - translator = stocks_translations.get_translator(menu="stocks", command="load") parser = translator.parser @@ -181,127 +182,21 @@ class StocksController(StockBaseController): @log_start_end(log=logger) def call_search(self, other_args: List[str]): """Process search command.""" - parser = argparse.ArgumentParser( - add_help=False, - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - prog="search", - description="Show companies matching the search query, country, sector, industry and/or exchange. " - "Note that by default only the United States exchanges are searched which tend to contain the most " - "extensive data for each company. To search all exchanges use the --all-exchanges flag.", - ) - parser.add_argument( - "-q", - "--query", - action="store", - dest="query", - type=str.lower, - default="", - nargs="+", - help="The search term used to find company tickers", - ) - clean_countries = [x.lower().replace(" ", "_") for x in self.country] - parser.add_argument( - "-c", - "--country", - default="", - choices=clean_countries, - dest="country", - metavar="country", - type=str.lower, - help="Search by country to find stocks matching the criteria", - ) - parser.add_argument( - "-s", - "--sector", - default="", - choices=stocks_helper.format_parse_choices(self.sector), - type=str.lower, - metavar="sector", - dest="sector", - help="Search by sector to find stocks matching the criteria", - ) - parser.add_argument( - "--industrygroup", - default="", - choices=stocks_helper.format_parse_choices(self.industry_group), - type=str.lower, - metavar="industry_group", - dest="industry_group", - help="Search by industry group to find stocks matching the criteria", - ) - parser.add_argument( - "-i", - "--industry", - default="", - choices=stocks_helper.format_parse_choices(self.industry), - type=str.lower, - metavar="industry", - dest="industry", - help="Search by industry to find stocks matching the criteria", - ) - parser.add_argument( - "-e", - "--exchange", - default="", - choices=stocks_helper.format_parse_choices(self.exchange), - type=str.lower, - metavar="exchange", - dest="exchange", - help="Search by a specific exchange to find stocks matching the criteria", - ) - parser.add_argument( - "--exchangecountry", - default="", - choices=stocks_helper.format_parse_choices( - list(stocks_helper.market_coverage_suffix.keys()) - ), - type=str.lower, - metavar="exchange_country", - dest="exchange_country", - help="Search by a specific country and all its exchanges to find stocks matching the criteria", - ) - parser.add_argument( - "-a", - "--all-exchanges", - default=False, - action="store_true", - dest="all_exchanges", - help="Whether to search all exchanges, without this option only the United States market is searched.", - ) - if other_args and "-" not in other_args[0][0]: - other_args.insert(0, "-q") + translator = stocks_translations.get_translator(menu="stocks", command="search") + parser = translator.parser + if ns_parser := self.parse_known_args_and_warn( - parser, - other_args, - EXPORT_ONLY_RAW_DATA_ALLOWED, + parser=parser, + other_args=other_args, + export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED, limit=10, ): - # Mapping - sector = stocks_helper.map_parse_choices(self.sector)[ns_parser.sector] - industry = stocks_helper.map_parse_choices(self.industry)[ - ns_parser.industry - ] - industry_group = stocks_helper.map_parse_choices(self.industry_group)[ - ns_parser.industry_group - ] - exchange = stocks_helper.map_parse_choices(self.exchange)[ - ns_parser.exchange - ] - exchange_country = stocks_helper.map_parse_choices( - list(stocks_helper.market_coverage_suffix.keys()) - )[ns_parser.exchange_country] + c_out = translator.execute_func(parsed_args=ns_parser) - stocks_helper.search( - query=" ".join(ns_parser.query), - country=ns_parser.country, - sector=sector, - industry_group=industry_group, - industry=industry, - exchange=exchange, - exchange_country=exchange_country, - all_exchanges=ns_parser.all_exchanges, - limit=ns_parser.limit, - ) + if c_out.error: + console.print(f"[red]{c_out.error}[/]\n") + else: + console.print(c_out.results) @log_start_end(log=logger) def call_tob(self, other_args: List[str]):