Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Pretty Pydantic ValidationError exceptions #6130

Merged
merged 9 commits into from
Feb 27, 2024
32 changes: 27 additions & 5 deletions openbb_platform/core/openbb_core/app/static/utils/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from openbb_core.app.model.abstract.error import OpenBBError
from openbb_core.env import Env
from pydantic import validate_call
from pydantic import ValidationError, validate_call
from typing_extensions import ParamSpec

P = ParamSpec("P")
Expand Down Expand Up @@ -44,14 +44,36 @@ def exception_handler(func: Callable[P, R]) -> Callable[P, R]:
"""Handle exceptions, attempting to focus on the last call from the traceback."""

@wraps(func)
def wrapper(*args, **kwargs):
def wrapper(*f_args, **f_kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
return func(*f_args, **f_kwargs)
except (ValidationError, Exception) as e:
if Env().DEBUG_MODE:
raise
if isinstance(e, ValidationError):
error_list = []

validation_error = f"{e.error_count()} validations errors in {e.title}"
for error in e.errors():
arg_error = f"Arg {error['loc'][0]} ->\n"
error_details = (
f" {error['msg']} "
f"[validation_error_type={error['type']}, "
f"input_type={type(error['input']).__name__}, "
f"input_value={error['input']}]\n"
)
error_info = f" For further information visit {error['url']}\n"
error_list.append(arg_error + error_details + error_info)

error_list.insert(0, validation_error)
error_str = "\n".join(error_list)
raise OpenBBError(
f"\nType -> ValidationError \n\nDetails -> {error_str}"
) from None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo, this should be from e, otherwise it will point to the decorator instead of the actual code that's breaking

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we do from e then we are adding the context of the original exception which is wrapped by OpenBBError. To reduce the traceback call we use from None so that the context of the original exception is not used and so that is suppressed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's keep it that way until we find a good solution for the traceback suppression, then!


# If the error is not a ValidationError, then it is a generic exception
raise OpenBBError(
f"\nType -> {e.__class__.__name__}\n\nDetail -> {str(e)}"
f"\nType -> {e.original.original.__class__.__name__}\n\nDetail -> {str(e)}"
) from None
hjoaquim marked this conversation as resolved.
Show resolved Hide resolved

return wrapper
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class FMPIndexHistoricalQueryParams(IndexHistoricalQueryParams):
Field(default="1day", description="Data granularity.")
)

@field_validator("interval")
@field_validator("interval", mode="before", check_fields=True)
@classmethod
def map_interval(cls, v):
"""Map the interval from standard to the FMP format."""
Expand Down Expand Up @@ -104,9 +104,12 @@ async def aextract_data(

return await get_data_many(url, "historical", **kwargs)

# pylint: disable=unused-argument
@staticmethod
def transform_data(
query: FMPIndexHistoricalQueryParams, data: List[Dict], **kwargs: Any
query: FMPIndexHistoricalQueryParams,
data: List[Dict],
**kwargs: Any,
) -> List[FMPIndexHistoricalData]:
"""Return the transformed data."""
return [
Expand Down
Loading