mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
Hotfix/keys menu improvements (#4699)
* avoid keys to alwyas check status * ruff * improve text on show flag * removing force flag * use bool * improve help functionality * fix tests * trying to fool pylit * using exception handling * printing the result for a single key * Don't check status if --help * black --------- Co-authored-by: montezdesousa <79287829+montezdesousa@users.noreply.github.com> Co-authored-by: Diogo Sousa <montezdesousa@gmail.com>
This commit is contained in:
@@ -5,7 +5,7 @@ __docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Callable, Dict, List, Optional
|
||||
|
||||
from openbb_terminal import (
|
||||
keys_model,
|
||||
@@ -38,9 +38,10 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
|
||||
API_DICT = keys_model.API_DICT
|
||||
API_LIST = list(API_DICT.keys())
|
||||
CHOICES_COMMANDS: List[str] = ["mykeys"] + API_LIST
|
||||
CHOICES_COMMANDS: List[str] = ["mykeys", "status"] + API_LIST
|
||||
PATH = "/keys/"
|
||||
status_dict: Dict = {}
|
||||
help_status_text: str = ""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -56,21 +57,24 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
|
||||
self.completer = NestedCompleter.from_nested_dict(choices)
|
||||
|
||||
def check_keys_status(self) -> None:
|
||||
"""Check keys status"""
|
||||
for api in optional_rich_track(self.API_LIST, desc="Checking keys status"):
|
||||
try:
|
||||
self.status_dict[api] = getattr(
|
||||
keys_model, "check_" + str(api) + "_key"
|
||||
)()
|
||||
except Exception:
|
||||
self.status_dict[api] = str(
|
||||
keys_model.KeyStatus.DEFINED_TEST_INCONCLUSIVE
|
||||
)
|
||||
def get_check_keys_function(self, key: str) -> Callable:
|
||||
"""Get check `key` function from keys_model"""
|
||||
return getattr(keys_model, f"check_{key}_key")
|
||||
|
||||
def print_help(self):
|
||||
def check_keys_status(self, reevaluate: bool = False) -> None:
|
||||
"""Check keys status"""
|
||||
if not self.status_dict or reevaluate:
|
||||
for api in optional_rich_track(self.API_LIST, desc="Checking keys status"):
|
||||
try:
|
||||
self.status_dict[api] = self.get_check_keys_function(api)()
|
||||
except Exception:
|
||||
self.status_dict[api] = str(
|
||||
keys_model.KeyStatus.DEFINED_TEST_INCONCLUSIVE
|
||||
)
|
||||
|
||||
def print_help(self, update_status: bool = False, reevaluate: bool = False):
|
||||
"""Print help"""
|
||||
self.check_keys_status()
|
||||
self.check_keys_status(reevaluate=reevaluate)
|
||||
mt = MenuText("keys/")
|
||||
mt.add_param(
|
||||
"_source",
|
||||
@@ -82,32 +86,32 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
mt.add_info("_keys_")
|
||||
mt.add_raw("\n")
|
||||
mt.add_cmd("mykeys")
|
||||
mt.add_cmd("status")
|
||||
mt.add_raw("\n")
|
||||
mt.add_info("_status_")
|
||||
|
||||
for cmd_name, status_msg in self.status_dict.items():
|
||||
api_name = self.API_DICT[cmd_name]
|
||||
status_color_map = {
|
||||
keys_model.KeyStatus.DEFINED_TEST_PASSED.value: "green",
|
||||
keys_model.KeyStatus.DEFINED_TEST_FAILED.value: "red",
|
||||
keys_model.KeyStatus.DEFINED_NOT_TESTED.value: "yellow",
|
||||
keys_model.KeyStatus.DEFINED_TEST_INCONCLUSIVE.value: "yellow",
|
||||
keys_model.KeyStatus.NOT_DEFINED.value: "grey30",
|
||||
}
|
||||
|
||||
c = "grey30"
|
||||
if status_msg == str(keys_model.KeyStatus.DEFINED_TEST_PASSED):
|
||||
c = "green"
|
||||
elif status_msg == str(keys_model.KeyStatus.DEFINED_TEST_FAILED):
|
||||
c = "red"
|
||||
elif status_msg == str(keys_model.KeyStatus.DEFINED_NOT_TESTED):
|
||||
c = "yellow"
|
||||
elif status_msg == str(keys_model.KeyStatus.DEFINED_TEST_INCONCLUSIVE):
|
||||
c = "yellow"
|
||||
elif status_msg == str(keys_model.KeyStatus.NOT_DEFINED):
|
||||
c = "grey30"
|
||||
if not self.help_status_text or update_status:
|
||||
for cmd_name, status_msg in self.status_dict.items():
|
||||
api_name = self.API_DICT[cmd_name]
|
||||
|
||||
if status_msg is None:
|
||||
status_msg = str(keys_model.KeyStatus.NOT_DEFINED)
|
||||
mt.add_raw(
|
||||
f" [cmds]{cmd_name}[/cmds] {(20 - len(cmd_name)) * ' '}"
|
||||
f" [{c}] {api_name} {(25 - len(api_name)) * ' '} {translate(status_msg)} [/{c}]\n"
|
||||
)
|
||||
c = status_color_map.get(status_msg, "grey30")
|
||||
status_msg = status_msg or keys_model.KeyStatus.NOT_DEFINED.value
|
||||
|
||||
console.print(text=mt.menu_text, menu="Keys")
|
||||
mt.add_raw(
|
||||
f" [cmds]{cmd_name}[/cmds] {(20 - len(cmd_name)) * ' '}"
|
||||
f" [{c}] {api_name} {(25 - len(api_name)) * ' '} {translate(status_msg)} [/{c}]\n"
|
||||
)
|
||||
self.help_status_text = mt.menu_text
|
||||
|
||||
console.print(text=self.help_status_text, menu="Keys")
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_mykeys(self, other_args: List[str]):
|
||||
@@ -119,7 +123,12 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
description="Display current keys.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s", "--show", type=bool, dest="show", help="show", default=False
|
||||
"-s",
|
||||
"--show",
|
||||
type=bool,
|
||||
dest="show",
|
||||
help="See keys in raw text instead of the default protected display.",
|
||||
default=False,
|
||||
)
|
||||
if other_args and "-s" in other_args[0]:
|
||||
other_args.insert(1, "True")
|
||||
@@ -137,6 +146,50 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
else None,
|
||||
)
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_status(self, other_args: List[str]):
|
||||
"""Display current keys status with the option to force the check"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="status",
|
||||
description="Reevaluate keys status.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-k",
|
||||
"--key",
|
||||
type=str,
|
||||
dest="key",
|
||||
help="Force the status to reevaluate for a specific key.",
|
||||
default=None,
|
||||
)
|
||||
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-k")
|
||||
|
||||
ns_parser = self.parse_known_args_and_warn(
|
||||
parser, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
|
||||
is_key = bool(ns_parser and ns_parser.key)
|
||||
|
||||
if is_key:
|
||||
if ns_parser.key in self.API_LIST:
|
||||
try:
|
||||
status = self.get_check_keys_function(ns_parser.key)(True)
|
||||
self.status_dict[ns_parser.key] = status
|
||||
console.print("")
|
||||
except Exception:
|
||||
status = keys_model.KeyStatus.DEFINED_TEST_INCONCLUSIVE
|
||||
self.status_dict[ns_parser.key] = str(status)
|
||||
console.print(f"{status.colorize()}\n")
|
||||
else:
|
||||
console.print(f"[red]Key `{ns_parser.key}` is not a valid key.[/red]")
|
||||
return
|
||||
|
||||
if "-h" not in other_args and "--help" not in other_args:
|
||||
self.print_help(update_status=True, reevaluate=not is_key)
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_av(self, other_args: List[str]):
|
||||
"""Process av command"""
|
||||
|
||||
@@ -49,8 +49,9 @@ logger = logging.getLogger(__name__)
|
||||
# This format is used by the KeysController and get_keys_info().
|
||||
# E.g. tokenterminal -> set_tokenterminal_key & check_tokenterminal_key
|
||||
#
|
||||
# Don't forget to add the set function to api.py endpoints dictionary.
|
||||
# E.g. "keys.tokenterminal": {"model": "openbb_terminal.keys_model.set_tokenterminal_key"},
|
||||
# Don't forget to add it to the SDK.
|
||||
# E.g. `keys.av,keys_model.set_av_key`
|
||||
# For more info, please refer to the CONTRIBUTING.md file.
|
||||
|
||||
API_DICT: Dict = {
|
||||
"av": "ALPHA_VANTAGE",
|
||||
|
||||
1
openbb_terminal/miscellaneous/i18n/en.yml
vendored
1
openbb_terminal/miscellaneous/i18n/en.yml
vendored
@@ -35,6 +35,7 @@ en:
|
||||
keys/_source: Source
|
||||
keys/_keys_: This menu allows you to set your own API keys. Type 'about' for more information
|
||||
keys/mykeys: get your defined keys
|
||||
keys/status: reevaluate keys status
|
||||
keys/_status_: Status
|
||||
defined, test passed: defined, test passed
|
||||
defined, test failed: defined, test failed
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"companyShortName": "Apple", "companyFullName": "Apple Inc.", "risks": ["Competition Risk"], "primary_industry": "Consumer Electronics", "primary_sector": "Technology"}
|
||||
@@ -1 +0,0 @@
|
||||
{"message": "Invalid Authorization Header"}
|
||||
@@ -0,0 +1 @@
|
||||
{"companyShortName": "Freeport-McMoRan", "companyFullName": "Freeport-McMoRan Inc.", "risks": ["Competition Risk"], "primary_industry": "Metals & Mining", "primary_sector": "Basic Materials"}
|
||||
@@ -1 +0,0 @@
|
||||
{"message": "Invalid Authorization Header"}
|
||||
@@ -0,0 +1 @@
|
||||
{"companyShortName": "Tesla", "companyFullName": "Tesla, Inc.", "risks": ["Competition Risk"], "primary_industry": "Auto Manufacturers", "primary_sector": "Consumer Cyclical"}
|
||||
@@ -1 +0,0 @@
|
||||
{"message": "Invalid Authorization Header"}
|
||||
@@ -1 +0,0 @@
|
||||
["FCX", "BMY", "SCHW", "WMT", "GM", "EXC", "RTX", "CVX", "MSFT", "NRG", "ACN", "GOOGL", "V", "MDLZ", "F", "DHR", "TSLA", "SO", "AMT", "PG", "GE", "RJF", "MS", "IBM", "VZ", "AAPL", "USB", "LIN", "WAB", "JNJ", "MET", "PEP", "LLY", "KO", "WFC", "ABT", "TMO", "GD", "MCD", "TXN", "BKNG", "CVS", "LOW", "COF", "UNH", "AIG", "PFE", "MO", "ABBV", "JPM", "JEF", "CAT", "BAC", "CL", "MRK", "ORCL", "MA", "META", "CSX", "KHC", "AMD", "TMUS", "CTVA", "UPS", "DIS", "BRK-B", "PM", "AMZN", "LMT", "XOM", "CMCSA", "ADM", "AVGO", "NEE", "HON", "DUK", "COST", "WM", "CRM", "DOW", "CMS", "INTC", "UNP", "SPG", "FDX", "ADBE", "GILD", "MDT", "C", "SBUX", "AA", "QCOM", "AMGN", "BA", "BLK", "GOOG", "T", "WBA", "NVDA", "CSCO", "AXP", "COP", "BK", "NKE", "EMR", "CHTR", "MMM", "HD", "CF", "SF", "TGT", "GS", "PYPL", "STLD", "NFLX", "AMPH", "ASYS", "CPRX", "DAL", "KKR", "PRPH", "RUM", "SAVE", "STAG", "SYK", "TITN", "MODG", "WBD", "CELH", "KR", "SKLZ", "MSGS", "HUBS", "BABA", "UBER", "DG", "SQ", "BX", "SOFI", "TPC", "CLVT", "STKS", "DWAC", "WSM", "TRMB", "CZR", "IQV", "JKHY", "SEE", "NTRS", "LAW", "TTWO", "ZBRA", "BEN", "AMCR", "RIVN", "K", "CSV", "LH", "MNTV", "ATRA", "NTAP", "CMA", "CRWD", "PFG", "FSLR", "LYB", "FTV", "TFC", "BIIB", "PKI", "ETR", "FDS", "SWKS", "OSIS", "HSIC", "KLAC", "CYTK", "IT", "NDAQ", "BALL", "SIRI", "DLR", "DFS", "PGR", "MOH", "STZ", "IFF", "UHS", "ZBH", "RBLX", "MGM", "WAL", "NDSN", "ENR", "CHRS", "CB", "EQR", "ADSK", "CME", "APA", "HRL", "OGN", "SLB", "FICO", "EZPW", "X", "IDXX", "KTOS", "BDX", "WTW", "CCL", "BR", "MOS", "IAC", "CLX", "NWS", "WAFD", "WHR", "MELI", "ABC", "EFX", "LRCX", "HPQ", "STE", "QTWO", "LVS", "LDOS", "TPR", "MPWR", "ALK", "WAT", "ABML", "LNT", "NEM", "WYNN", "AJG", "AAL", "CCI", "IEX", "AES", "ADI", "MTCH", "FAST", "AIZ", "VMC", "SBAC", "BIGC", "CDW", "BBBY", "EA", "NVR", "SRE", "DVN", "CAG", "ZTS", "AME", "CTLT", "FOX", "NCLH", "FITB", "PWR", "TAP", "WEC", "TDG", "FLT", "J", "VLO", "CBRE", "DLTR", "NOC", "MAS", "HPE", "PCG", "ES", "PARA", "CEG", "POOL", "HST", "SNA", "ABNB", "SEMR", "WVE", "GWW", "DPZ", "AMAT", "PEG", "SWK", "JCI", "VTR", "FMC", "WMB", "KEYS", "MAR", "AVB", "MKC", "MRVL", "MNST", "CHD", "BG", "ROP", "EL", "HII", "ZION", "QRVO", "MCK", "PNR", "ON", "XRAY", "NWSA", "INTA", "JBHT", "PSX", "CRL", "BCO", "JNPR", "HES", "REG", "DTE", "PXD", "HLT", "APTV", "GWRE", "BBW", "OVV", "ATO", "BLKB", "ANSS", "CTRA", "CMI", "HSY", "CSL", "WDAY", "CFG", "GPC", "KIM", "GL", "DD", "MMC", "PKG", "ITW", "WST", "OKE", "UAL", "PAYX", "PCAR", "HOLX", "EQT", "INCY", "CPRT", "AVY", "WDC", "SYF", "BSX", "SG", "DDOG", "SHW", "BXP", "TECH", "BF-B", "MCO", "LEN", "CTAS", "PLUG", "TRGP", "ROST", "APH", "ED", "CHRW", "PLTR", "RF", "EQIX", "BKR", "SPT", "PH", "DXCM", "EW", "KMB", "COO", "ELV", "AZO", "ESS", "WRB", "MPC", "XYL", "LW", "EXPE", "PAYC", "DHI", "VTRS", "NOW", "EPAM", "VRSK", "HBAN", "STX", "EXPD", "DRI", "CMG", "HCA", "LVOX", "LCID", "D", "SCCO", "CI", "ETN", "GLW", "SNPS", "BIO", "GPK", "ODFL", "PHM", "WRK", "CE", "URI", "PRU", "CINF", "INVH", "ILMN", "MHK", "ORLY", "UDR", "GRMN", "MKTX", "PPL", "VRTX", "ROK", "DVA", "ICE", "CNP", "MRO", "CPB", "OMC", "KEY", "IRM", "SPGI", "EIX", "TER", "SYY", "BWA", "ANET", "EVBG", "ALLY", "ECL", "CDNS", "FE", "CNC", "ENPH", "AKAM", "PANW", "CC", "NSC", "DE", "PLD", "TRV", "DOV", "UBX", "NFG", "DGX", "MSCI", "SEDG", "EVRG", "AFL", "GEN", "EMN", "ENFN", "KMI", "PODD", "GIS", "TJX", "TEL", "PNW", "TFX", "L", "MED", "OXY", "UGI", "REGN", "GME", "RE", "ZM", "FISV", "ATVI", "BBIO", "MSI", "CAH", "ALB", "IR", "TSCO", "FIS", "CPT", "AMC", "TSN", "HWM", "LZB", "FOXA", "EBAY", "MTB", "TYL", "LKQ", "AWK", "IVZ", "INTU", "RCL", "TWLO", "GPN", "PRO", "KMX", "CHPT", "AOS", "CSGP", "MU", "ZI", "XEL", "ADP", "RSG", "MRNA", "LNC", "VICI", "MTD", "PTC", "DISH", "HUM", "ACGL", "NI", "DXC", "BRO", "SPSC", "NET", "VFC", "WELL", "LHX", "RL", "LYV", "SIVB", "PII", "APD", "PRI", "LUV", "FRC", "EOG", "MAA", "FANG", "AEE", "GEHC", "EGAN", "OTIS", "YUM", "DCT", "TT", "CXM", "VRSN", "FFIV", "NKTX", "FTNT", "LULU", "SJM", "ALGN", "KDP", "AMP", "HAS", "PEAK", "ETSY", "EXR", "CARR", "PPG", "MTTR", "O", "AAP", "RMD", "BBWI", "VSTO", "WY", "DKS", "ALL", "BBY", "AON", "TXT", "FRT", "RHI", "HIG", "MCHP", "ASMB", "PSA", "PNC", "SGEN", "STT", "ROL", "MLM", "NWL", "CDAY", "IP", "TROW", "INSE", "BAX", "GNRC", "MLNK", "NXPI", "ULTA", "ZS", "AEP", "COLL", "ALLE", "IPG", "TDY", "NUE", "A", "CBOE", "CTSH", "ARE", "HAL", "LAZR", "ISRG"]
|
||||
@@ -10,6 +10,36 @@ from openbb_terminal.common.ultima_newsmonitor_model import (
|
||||
supported_terms,
|
||||
)
|
||||
|
||||
MOCK_REQUEST_RESPONSE = {
|
||||
"TSLA": {
|
||||
"companyShortName": "Tesla",
|
||||
"companyFullName": "Tesla, Inc.",
|
||||
"risks": [
|
||||
"Competition Risk",
|
||||
],
|
||||
"primary_industry": "Auto Manufacturers",
|
||||
"primary_sector": "Consumer Cyclical",
|
||||
},
|
||||
"AAPL": {
|
||||
"companyShortName": "Apple",
|
||||
"companyFullName": "Apple Inc.",
|
||||
"risks": [
|
||||
"Competition Risk",
|
||||
],
|
||||
"primary_industry": "Consumer Electronics",
|
||||
"primary_sector": "Technology",
|
||||
},
|
||||
"FCX": {
|
||||
"companyShortName": "Freeport-McMoRan",
|
||||
"companyFullName": "Freeport-McMoRan Inc.",
|
||||
"risks": [
|
||||
"Competition Risk",
|
||||
],
|
||||
"primary_industry": "Metals & Mining",
|
||||
"primary_sector": "Basic Materials",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.vcr
|
||||
@pytest.mark.parametrize(
|
||||
@@ -27,19 +57,48 @@ def test_get_news(term, recorder):
|
||||
recorder.capture(df)
|
||||
|
||||
|
||||
# @pytest.mark.default_cassette("test_supported_terms.yaml")
|
||||
# @pytest.mark.vcr
|
||||
def test_supported_terms(recorder):
|
||||
r = supported_terms()
|
||||
recorder.capture(r)
|
||||
def test_supported_terms(mocker):
|
||||
# MOCK REQUEST
|
||||
attrs = {
|
||||
"status_code": 200,
|
||||
"json.return_value": list(MOCK_REQUEST_RESPONSE.keys()),
|
||||
}
|
||||
mock_response = mocker.Mock(**attrs)
|
||||
|
||||
mocker.patch(
|
||||
target="openbb_terminal.common.ultima_newsmonitor_model.request",
|
||||
new=mocker.Mock(return_value=mock_response),
|
||||
)
|
||||
terms = supported_terms()
|
||||
assert terms == list(MOCK_REQUEST_RESPONSE.keys())
|
||||
|
||||
|
||||
# @pytest.mark.default_cassette("test_get_company_info.yaml")
|
||||
# @pytest.mark.vcr
|
||||
@pytest.mark.parametrize(
|
||||
"ticker",
|
||||
["AAPL", "TSLA", "FCX", "asdf$#"],
|
||||
"ticker, response",
|
||||
[
|
||||
("AAPL", MOCK_REQUEST_RESPONSE["AAPL"]),
|
||||
("TSLA", MOCK_REQUEST_RESPONSE["TSLA"]),
|
||||
("FCX", MOCK_REQUEST_RESPONSE["FCX"]),
|
||||
("asdf$#", {}),
|
||||
],
|
||||
)
|
||||
def test_get_company_info(ticker, recorder):
|
||||
def test_get_company_info(ticker, response, recorder, mocker):
|
||||
# MOCK SUPPORTED TERMS
|
||||
mocker.patch(
|
||||
target="openbb_terminal.common.ultima_newsmonitor_model.supported_terms",
|
||||
new=mocker.Mock(return_value=list(MOCK_REQUEST_RESPONSE.keys())),
|
||||
)
|
||||
|
||||
# MOCK REQUEST
|
||||
attrs = {
|
||||
"status_code": 200,
|
||||
"json.return_value": response,
|
||||
}
|
||||
mock_response = mocker.Mock(**attrs)
|
||||
|
||||
mocker.patch(
|
||||
target="openbb_terminal.common.ultima_newsmonitor_model.request",
|
||||
new=mocker.Mock(return_value=mock_response),
|
||||
)
|
||||
df = get_company_info(ticker=ticker)
|
||||
recorder.capture(df)
|
||||
|
||||
Reference in New Issue
Block a user