diff --git a/projects/fal/src/fal/api.py b/projects/fal/src/fal/api.py index 459d0570..65f64c40 100644 --- a/projects/fal/src/fal/api.py +++ b/projects/fal/src/fal/api.py @@ -40,6 +40,7 @@ from typing_extensions import Concatenate, ParamSpec import fal.flags as flags +from fal.exceptions import FalServerlessException from fal._serialization import include_modules_from, patch_pickle from fal.logging.isolate import IsolateLogPrinter from fal.sdk import ( @@ -70,12 +71,12 @@ @dataclass -class FalServerlessError(Exception): +class FalServerlessError(FalServerlessException): message: str @dataclass -class InternalFalServerlessError(Exception): +class InternalFalServerlessError(FalServerlessException): message: str @@ -183,7 +184,7 @@ def wrapper( return wrapper -class UserFunctionException(Exception): +class UserFunctionException(FalServerlessException): pass @@ -198,6 +199,8 @@ def _prepare_partial_func( def wrapper(*remote_args: ArgsT.args, **remote_kwargs: ArgsT.kwargs) -> ReturnT: try: result = func(*remote_args, *args, **remote_kwargs, **kwargs) + except FalServerlessException: + raise except Exception as exc: tb = exc.__traceback__ if tb is not None and tb.tb_next is not None: diff --git a/projects/fal/src/fal/exceptions/__init__.py b/projects/fal/src/fal/exceptions/__init__.py index 1bd11be0..31969202 100644 --- a/projects/fal/src/fal/exceptions/__init__.py +++ b/projects/fal/src/fal/exceptions/__init__.py @@ -1,8 +1,8 @@ from __future__ import annotations +from ._base import FalServerlessException # noqa: F401 from .handlers import ( BaseExceptionHandler, - FalServerlessExceptionHandler, GrpcExceptionHandler, UserFunctionExceptionHandler, ) @@ -20,7 +20,6 @@ class ApplicationExceptionHandler: _handlers: list[BaseExceptionHandler] = [ GrpcExceptionHandler(), - FalServerlessExceptionHandler(), UserFunctionExceptionHandler(), ] diff --git a/projects/fal/src/fal/exceptions/_base.py b/projects/fal/src/fal/exceptions/_base.py index 17994cd7..885a2f94 100644 --- a/projects/fal/src/fal/exceptions/_base.py +++ b/projects/fal/src/fal/exceptions/_base.py @@ -3,15 +3,4 @@ class FalServerlessException(Exception): """Base exception type for fal Serverless related flows and APIs.""" - - message: str - - hint: str | None - - def __init__(self, message: str, hint: str | None = None) -> None: - self.message = message - self.hint = hint - super().__init__(message) - - def __str__(self) -> str: - return self.message + (f"\nHint: {self.hint}" if self.hint else "") + pass diff --git a/projects/fal/src/fal/exceptions/auth.py b/projects/fal/src/fal/exceptions/auth.py index 1a0c5d6f..116c3e6a 100644 --- a/projects/fal/src/fal/exceptions/auth.py +++ b/projects/fal/src/fal/exceptions/auth.py @@ -4,10 +4,8 @@ class UnauthenticatedException(FalServerlessException): - """Exception that indicates that""" - def __init__(self) -> None: super().__init__( - message="You must be authenticated.", - hint="Login via `fal auth login` or make sure to setup fal keys correctly.", + "You must be authenticated. " + "Login via `fal auth login` or make sure to setup fal keys correctly." ) diff --git a/projects/fal/src/fal/exceptions/handlers.py b/projects/fal/src/fal/exceptions/handlers.py index 7b584c82..36b06361 100644 --- a/projects/fal/src/fal/exceptions/handlers.py +++ b/projects/fal/src/fal/exceptions/handlers.py @@ -3,7 +3,6 @@ from typing import TYPE_CHECKING, Generic, TypeVar from grpc import Call as RpcCall -from rich.markdown import Markdown from fal.console import console from fal.console.icons import CROSS_ICON @@ -11,7 +10,6 @@ if TYPE_CHECKING: from fal.api import UserFunctionException -from ._base import FalServerlessException ExceptionType = TypeVar("ExceptionType", bound=BaseException) @@ -23,24 +21,11 @@ def should_handle(self, _: Exception) -> bool: return True def handle(self, exception: ExceptionType): + msg = f"{CROSS_ICON} {str(exception)}" cause = exception.__cause__ - if cause is None: - console.print(str(exception)) - else: - console.print(f"{str(exception)}: {str(cause)}") - - -class FalServerlessExceptionHandler(BaseExceptionHandler[FalServerlessException]): - """Handle fal Serverless exceptions""" - - def should_handle(self, exception: Exception) -> bool: - return isinstance(exception, FalServerlessException) - - def handle(self, exception: FalServerlessException): - console.print(f"{CROSS_ICON} {exception.message}") - if exception.hint is not None: - console.print(Markdown(f"**Hint:** {exception.hint}")) - console.print() + if cause is not None: + msg += f": {str(cause)}" + console.print(msg) class GrpcExceptionHandler(BaseExceptionHandler[RpcCall]): diff --git a/projects/fal/src/fal/workflows.py b/projects/fal/src/fal/workflows.py index a3cdd216..73f03722 100644 --- a/projects/fal/src/fal/workflows.py +++ b/projects/fal/src/fal/workflows.py @@ -18,6 +18,7 @@ import fal from fal import flags +from fal.exceptions import FalServerlessException from fal.rest_client import REST_CLIENT JSONType = Union[dict[str, Any], list[Any], str, int, float, bool, None, "Leaf"] @@ -31,7 +32,7 @@ WORKFLOW_EXPORT_VERSION = "0.1" -class WorkflowSyntaxError(Exception): +class WorkflowSyntaxError(FalServerlessException): pass