From cf6a7aa970d1d68578ebbace77e8da26b75771ef Mon Sep 17 00:00:00 2001 From: John Seong <39040639+sandole@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:36:20 -0800 Subject: [PATCH] fix(cli): move custom Field kwargs to json_schema_extra for mypy compatibility (#7362) Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> --- .../controllers/base_platform_controller.py | 2 +- .../controllers/settings_controller.py | 26 +++-- cli/openbb_cli/models/settings.py | 102 ++++++++++++------ .../openbb_core/app/static/package_builder.py | 2 +- .../econometrics_router.py | 10 +- .../deribit/openbb_deribit/utils/helpers.py | 14 +-- .../ecb/openbb_ecb/models/yield_curve.py | 2 +- .../models/svensson_yield_curve.py | 1 - .../models/total_factor_productivity.py | 6 +- .../utils/fomc_documents.py | 2 +- .../sec/openbb_sec/utils/parse_13f.py | 2 +- 11 files changed, 104 insertions(+), 65 deletions(-) diff --git a/cli/openbb_cli/controllers/base_platform_controller.py b/cli/openbb_cli/controllers/base_platform_controller.py index c0aeb2e147c..0c615b12717 100644 --- a/cli/openbb_cli/controllers/base_platform_controller.py +++ b/cli/openbb_cli/controllers/base_platform_controller.py @@ -236,7 +236,7 @@ class PlatformController(BaseController): if not export: obbject.show() elif session.settings.USE_INTERACTIVE_DF and not export: - obbject.charting.table() + obbject.charting.table() # type: ignore[attr-defined] else: if isinstance(df.columns, pd.RangeIndex): df.columns = [str(i) for i in df.columns] diff --git a/cli/openbb_cli/controllers/settings_controller.py b/cli/openbb_cli/controllers/settings_controller.py index 37b66ccb798..d38578eee7b 100644 --- a/cli/openbb_cli/controllers/settings_controller.py +++ b/cli/openbb_cli/controllers/settings_controller.py @@ -3,7 +3,7 @@ import argparse from functools import partial, update_wrapper from types import MethodType -from typing import Literal, get_origin +from typing import Any, Literal, cast, get_origin from openbb_cli.config.menu_text import MenuText from openbb_cli.controllers.base_controller import BaseController @@ -13,20 +13,26 @@ from openbb_cli.session import Session session = Session() +def _get_extra(field: Any) -> dict[str, Any]: + """Safely extract json_schema_extra as a dict.""" + extra = field.json_schema_extra + return cast(dict[str, Any], extra) if isinstance(extra, dict) else {} + + class SettingsController(BaseController): """Settings Controller class.""" - _COMMANDS = { - v.json_schema_extra.get("command"): { - "command": (v.json_schema_extra or {}).get("command"), - "group": (v.json_schema_extra or {}).get("group"), + _COMMANDS: dict[str, dict[str, Any]] = { + _get_extra(v).get("command", ""): { + "command": _get_extra(v).get("command"), + "group": _get_extra(v).get("group"), "description": v.description, "annotation": v.annotation, "field_name": k, } for k, v in sorted( session.settings.model_fields.items(), - key=lambda item: (item[1].json_schema_extra or {}).get("command", ""), + key=lambda item: _get_extra(item[1]).get("command", ""), ) if v.json_schema_extra } @@ -39,9 +45,9 @@ class SettingsController(BaseController): super().__init__(queue) for cmd, field in self._COMMANDS.items(): group = field.get("group") - if group == SettingGroups.feature_flags: + if group == SettingGroups.feature_flags.value: self._generate_command(cmd, field, "toggle") - elif group == SettingGroups.preferences: + elif group == SettingGroups.preferences.value: self._generate_command(cmd, field, "set") self.update_completer(self.choices_default) @@ -50,7 +56,7 @@ class SettingsController(BaseController): mt = MenuText("settings/") mt.add_info("Feature Flags") for k, f in self._COMMANDS.items(): - if f.get("group") == SettingGroups.feature_flags: + if f.get("group") == SettingGroups.feature_flags.value: mt.add_setting( name=k, status=getattr(session.settings, f["field_name"]), @@ -59,7 +65,7 @@ class SettingsController(BaseController): mt.add_raw("\n") mt.add_info("Preferences") for k, f in self._COMMANDS.items(): - if f.get("group") == SettingGroups.preferences: + if f.get("group") == SettingGroups.preferences.value: mt.add_cmd( name=k, description=f["description"], diff --git a/cli/openbb_cli/models/settings.py b/cli/openbb_cli/models/settings.py index f0c9fa78b59..6ac9909a338 100644 --- a/cli/openbb_cli/models/settings.py +++ b/cli/openbb_cli/models/settings.py @@ -41,106 +41,140 @@ class Settings(BaseModel): FILE_OVERWRITE: bool = Field( default=False, description="whether to overwrite Excel files if they already exists", - command="overwrite", - group=SettingGroups.feature_flags, + json_schema_extra={ + "command": "overwrite", + "group": SettingGroups.feature_flags.value, + }, ) SHOW_VERSION: bool = Field( default=True, description="whether to show the version in the bottom right corner", - command="version", - group=SettingGroups.feature_flags, + json_schema_extra={ + "command": "version", + "group": SettingGroups.feature_flags.value, + }, ) USE_INTERACTIVE_DF: bool = Field( default=True, description="display tables in interactive window", - command="interactive", - group=SettingGroups.feature_flags, + json_schema_extra={ + "command": "interactive", + "group": SettingGroups.feature_flags.value, + }, ) USE_CLEAR_AFTER_CMD: bool = Field( default=False, description="clear console after each command", - command="cls", - group=SettingGroups.feature_flags, + json_schema_extra={ + "command": "cls", + "group": SettingGroups.feature_flags.value, + }, ) USE_DATETIME: bool = Field( default=True, description="whether to show the date and time before the flair", - command="datetime", - group=SettingGroups.feature_flags, + json_schema_extra={ + "command": "datetime", + "group": SettingGroups.feature_flags.value, + }, ) USE_PROMPT_TOOLKIT: bool = Field( default=True, description="enable prompt toolkit (autocomplete and history)", - command="promptkit", - group=SettingGroups.feature_flags, + json_schema_extra={ + "command": "promptkit", + "group": SettingGroups.feature_flags.value, + }, ) ENABLE_EXIT_AUTO_HELP: bool = Field( default=True, description="automatically print help when quitting menu", - command="exithelp", - group=SettingGroups.feature_flags, + json_schema_extra={ + "command": "exithelp", + "group": SettingGroups.feature_flags.value, + }, ) ENABLE_RICH_PANEL: bool = Field( default=True, description="enable colorful rich CLI panel", - command="richpanel", - group=SettingGroups.feature_flags, + json_schema_extra={ + "command": "richpanel", + "group": SettingGroups.feature_flags.value, + }, ) TOOLBAR_HINT: bool = Field( default=True, description="displays usage hints in the bottom toolbar", - command="tbhint", - group=SettingGroups.feature_flags, + json_schema_extra={ + "command": "tbhint", + "group": SettingGroups.feature_flags.value, + }, ) SHOW_MSG_OBBJECT_REGISTRY: bool = Field( default=False, description="show obbject registry message after a new result is added", - command="obbject_msg", - group=SettingGroups.feature_flags, + json_schema_extra={ + "command": "obbject_msg", + "group": SettingGroups.feature_flags.value, + }, ) # PREFERENCES TIMEZONE: Literal[tuple(all_timezones)] = Field( # type: ignore[valid-type] default="America/New_York", description="pick timezone", - command="timezone", - group=SettingGroups.preferences, + json_schema_extra={ + "command": "timezone", + "group": SettingGroups.preferences.value, + }, ) FLAIR: Literal[tuple(AVAILABLE_FLAIRS)] = Field( # type: ignore[valid-type] default=":openbb", description="choose flair icon", - command="flair", - group=SettingGroups.preferences, + json_schema_extra={ + "command": "flair", + "group": SettingGroups.preferences.value, + }, ) N_TO_KEEP_OBBJECT_REGISTRY: int = Field( default=10, description="define the maximum number of obbjects allowed in the registry", - command="obbject_res", - group=SettingGroups.preferences, + json_schema_extra={ + "command": "obbject_res", + "group": SettingGroups.preferences.value, + }, ) N_TO_DISPLAY_OBBJECT_REGISTRY: int = Field( default=5, description="define the maximum number of cached results to display on the help menu", - command="obbject_display", - group=SettingGroups.preferences, + json_schema_extra={ + "command": "obbject_display", + "group": SettingGroups.preferences.value, + }, ) RICH_STYLE: str = Field( default="dark", description="apply a custom rich style to the CLI", - command="console_style", - group=SettingGroups.preferences, + json_schema_extra={ + "command": "console_style", + "group": SettingGroups.preferences.value, + }, ) ALLOWED_NUMBER_OF_ROWS: int = Field( default=20, description="number of rows to show (when not using interactive tables).", - command="n_rows", - group=SettingGroups.preferences, + json_schema_extra={ + "command": "n_rows", + "group": SettingGroups.preferences.value, + }, ) ALLOWED_NUMBER_OF_COLUMNS: int = Field( default=5, description="number of columns to show (when not using interactive tables).", - command="n_cols", - group=SettingGroups.preferences, + json_schema_extra={ + "command": "n_cols", + "group": SettingGroups.preferences.value, + }, ) model_config = ConfigDict(validate_assignment=True) diff --git a/openbb_platform/core/openbb_core/app/static/package_builder.py b/openbb_platform/core/openbb_core/app/static/package_builder.py index 594b3d893ab..f803a0abd84 100644 --- a/openbb_platform/core/openbb_core/app/static/package_builder.py +++ b/openbb_platform/core/openbb_core/app/static/package_builder.py @@ -2527,7 +2527,7 @@ class DocstringGenerator: "provider" ) providers = ( - list(provider_field.type.__args__) + list(provider_field.type.__args__) # type: ignore[union-attr] if provider_field else [] ) diff --git a/openbb_platform/extensions/econometrics/openbb_econometrics/econometrics_router.py b/openbb_platform/extensions/econometrics/openbb_econometrics/econometrics_router.py index b4b9ec7249a..4852c8a9f42 100644 --- a/openbb_platform/extensions/econometrics/openbb_econometrics/econometrics_router.py +++ b/openbb_platform/extensions/econometrics/openbb_econometrics/econometrics_router.py @@ -286,7 +286,7 @@ def ols_regression_summary( clean_results["raw"] = str(results_summary) - return OBBject(results=clean_results) + return OBBject(results=clean_results) # type: ignore[arg-type] @router.command( @@ -349,7 +349,7 @@ def autocorrelation( X = sm.add_constant(get_target_columns(basemodel_to_df(data), x_columns)) y = get_target_column(basemodel_to_df(data), y_column) results = sm.OLS(y, X).fit() - return OBBject(results=Data(score=durbin_watson(results.resid))) + return OBBject(results=Data(score=durbin_watson(results.resid))) # type: ignore[call-arg] @router.command( @@ -429,7 +429,7 @@ def residual_autocorrelation( "fp_value": fp_value, } - return OBBject(results=results) + return OBBject(results=results) # type: ignore[arg-type] @router.command( @@ -499,7 +499,7 @@ def cointegration( "pvalue": pvalue, } - return OBBject(results=result) + return OBBject(results=result) # type: ignore[arg-type] @router.command( @@ -641,7 +641,7 @@ def unit_root( "nobs": nobs, "icbest": icbest, } - return OBBject(results=results) + return OBBject(results=results) # type: ignore[arg-type] @router.command( diff --git a/openbb_platform/providers/deribit/openbb_deribit/utils/helpers.py b/openbb_platform/providers/deribit/openbb_deribit/utils/helpers.py index 40e6b2c4cc3..e647abffcba 100644 --- a/openbb_platform/providers/deribit/openbb_deribit/utils/helpers.py +++ b/openbb_platform/providers/deribit/openbb_deribit/utils/helpers.py @@ -202,9 +202,9 @@ async def get_ticker_data(symbol: str) -> dict: try: response = await amake_request(url) - if response.get("error"): - raise OpenBBError(response.get("error")) - data = response.get("result", {}) + if response.get("error"): # type: ignore[union-attr] + raise OpenBBError(response.get("error")) # type: ignore[union-attr] + data = response.get("result", {}) # type: ignore[union-attr] stats = data.pop("stats", {}) return {**data, **stats} @@ -282,10 +282,10 @@ async def get_ohlc_data( async def get_one(url): """Get data from one url.""" json_response = await amake_request(url) - if json_response.get("error"): - raise ValueError(json_response["error"]) - if json_response.get("result"): - result = json_response["result"] + if json_response.get("error"): # type: ignore[union-attr] + raise ValueError(json_response["error"]) # type: ignore[call-overload] + if json_response.get("result"): # type: ignore[union-attr] + result = json_response["result"] # type: ignore[call-overload] df = DataFrame(result) df = ( df.drop(columns=["status"]) diff --git a/openbb_platform/providers/ecb/openbb_ecb/models/yield_curve.py b/openbb_platform/providers/ecb/openbb_ecb/models/yield_curve.py index 33a8332c1eb..873a666b0b0 100644 --- a/openbb_platform/providers/ecb/openbb_ecb/models/yield_curve.py +++ b/openbb_platform/providers/ecb/openbb_ecb/models/yield_curve.py @@ -134,7 +134,7 @@ class ECBYieldCurveFetcher( if not data: raise EmptyDataError("The request was returned empty.") dates = ( - query.date.split(",") + str(query.date).split(",") if query.date else [datetime.now().strftime("%Y-%m-%d")] ) diff --git a/openbb_platform/providers/federal_reserve/openbb_federal_reserve/models/svensson_yield_curve.py b/openbb_platform/providers/federal_reserve/openbb_federal_reserve/models/svensson_yield_curve.py index da17fc91f0a..b78725440e6 100644 --- a/openbb_platform/providers/federal_reserve/openbb_federal_reserve/models/svensson_yield_curve.py +++ b/openbb_platform/providers/federal_reserve/openbb_federal_reserve/models/svensson_yield_curve.py @@ -239,7 +239,6 @@ class FederalReserveSvenssonData(Data): } }, populate_by_name=True, - populate_by_alias=True, alias_generator=AliasGenerator( serialization_alias=lambda x: x, # Identity function to preserve field names ), diff --git a/openbb_platform/providers/federal_reserve/openbb_federal_reserve/models/total_factor_productivity.py b/openbb_platform/providers/federal_reserve/openbb_federal_reserve/models/total_factor_productivity.py index 1fd96914fe7..974dd18844c 100644 --- a/openbb_platform/providers/federal_reserve/openbb_federal_reserve/models/total_factor_productivity.py +++ b/openbb_platform/providers/federal_reserve/openbb_federal_reserve/models/total_factor_productivity.py @@ -494,14 +494,14 @@ class FederalReserveTfpData( field_schema["description"] = field_info.description if field_info.json_schema_extra: - field_schema.update(field_info.json_schema_extra) + field_schema.update(field_info.json_schema_extra) # type: ignore[arg-type] json_schema["properties"][field_name] = field_schema # Preserve x-widget_config from model_config.json_schema_extra config_extra = cls.model_config.get("json_schema_extra", {}) - if "x-widget_config" in config_extra: - json_schema["x-widget_config"] = config_extra["x-widget_config"] + if "x-widget_config" in config_extra: # type: ignore[operator] + json_schema["x-widget_config"] = config_extra["x-widget_config"] # type: ignore[index] return json_schema diff --git a/openbb_platform/providers/federal_reserve/openbb_federal_reserve/utils/fomc_documents.py b/openbb_platform/providers/federal_reserve/openbb_federal_reserve/utils/fomc_documents.py index 9fb76fe343d..d2b325d5acc 100644 --- a/openbb_platform/providers/federal_reserve/openbb_federal_reserve/utils/fomc_documents.py +++ b/openbb_platform/providers/federal_reserve/openbb_federal_reserve/utils/fomc_documents.py @@ -82,7 +82,7 @@ def get_current_fomc_documents(url: str | None = None) -> list: soup = BeautifulSoup(response.content, "html.parser") for link in soup.find_all("a"): - url = link.get("href", "") + url = link.get("href", "") # type: ignore[assignment] if "/newsevents/pressreleases" in url: continue diff --git a/openbb_platform/providers/sec/openbb_sec/utils/parse_13f.py b/openbb_platform/providers/sec/openbb_sec/utils/parse_13f.py index 43b442a1623..22ffab90ca5 100644 --- a/openbb_platform/providers/sec/openbb_sec/utils/parse_13f.py +++ b/openbb_platform/providers/sec/openbb_sec/utils/parse_13f.py @@ -139,7 +139,7 @@ async def parse_13f_hr(filing: str): info_table = soup.find_all("informationTable") if not info_table: - info_table = soup.find_all("table")[-1] + info_table = soup.find_all("table")[-1] # type: ignore[assignment] parsed_xml = xmltodict.parse( str(info_table[0]).replace("ns1:", "").replace("n1:", "") # type: ignore