-
Notifications
You must be signed in to change notification settings - Fork 32
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
Question: How do you use @effect.result with asyncio? #205
Comments
For this to work we would need a separate |
@dbrattli is it entail just copying Expression/expression/effect/result.py Line 15 in 5b043db
|
i've started using my own decorator for results, here it is below for refrence. It wraps async or sync functions to return a Result[T, Exception]. It will ensure the return type is not double wrapped and it retuns the correct typing. Unlike The LunaException and category is specific for my usecase and can just be replaced with any othter exception or TErr import inspect
import typing as t
from functools import wraps
from expression import Error, Ok, Result
from shared.common.models.luna_exception import LunaException
from shared.common.models.luna_exception_category import LunaExceptionCategory
TInputs = t.ParamSpec("TInputs")
TOutputs = t.TypeVar("TOutputs")
def as_result(fallback: LunaExceptionCategory | LunaException = LunaExceptionCategory.wrapped_exception):
"""Decorator to wrap a function in a Result.
Note: fallback_exception takes precedence over fallback_category.
Returns:
A function that returns a Result[TOutputs, LunaException]
"""
def translate_result(output: TOutputs) -> Result[TOutputs, LunaException]:
if isinstance(output, LunaException):
return Error(output)
elif isinstance(output, Result):
return output
elif isinstance(output, Exception):
raise output
else:
return Ok(output)
@t.overload
def decorator(
func: t.Callable[TInputs, Result[TOutputs, LunaException]],
) -> t.Callable[TInputs, Result[TOutputs, LunaException]]: ...
@t.overload
def decorator( # type: ignore
func: t.Callable[TInputs, t.Coroutine[t.Any, t.Any, Result[TOutputs, LunaException]]],
) -> t.Callable[TInputs, t.Coroutine[t.Any, t.Any, Result[TOutputs, LunaException]]]: ...
@t.overload
def decorator(
func: t.Callable[TInputs, t.Coroutine[t.Any, t.Any, TOutputs]],
) -> t.Callable[TInputs, t.Coroutine[t.Any, t.Any, Result[TOutputs, LunaException]]]: ...
@t.overload
def decorator(func: t.Callable[TInputs, TOutputs]) -> t.Callable[TInputs, Result[TOutputs, LunaException]]: ...
def decorator(
func: t.Callable[TInputs, TOutputs]
| t.Callable[TInputs, t.Coroutine[t.Any, t.Any, TOutputs]]
| t.Callable[TInputs, Result[TOutputs, LunaException]]
| t.Callable[TInputs, t.Coroutine[t.Any, t.Any, Result[TOutputs, LunaException]]],
) -> t.Callable[TInputs, Result[TOutputs, LunaException]] | t.Callable[TInputs, t.Coroutine[t.Any, t.Any, Result[TOutputs, LunaException]]]:
if inspect.iscoroutinefunction(func):
@wraps(func)
async def async_wrapper(*args: TInputs.args, **kwargs: TInputs.kwargs) -> Result[TOutputs, LunaException]:
try:
result = t.cast(TOutputs, await func(*args, **kwargs))
return translate_result(result)
except LunaException as e:
return Error(e)
except Exception as e:
if isinstance(fallback, LunaException):
fallback.set_cause(e)
return Error(fallback)
return Error(LunaException(fallback, cause=e))
return async_wrapper
else:
@wraps(func)
def sync_wrapper(*args: TInputs.args, **kwargs: TInputs.kwargs) -> Result[TOutputs, LunaException]:
try:
result = t.cast(TOutputs, func(*args, **kwargs))
return translate_result(result)
except LunaException as e:
return Error(e)
except Exception as e:
if isinstance(fallback, LunaException):
fallback.set_cause(e)
return Error(fallback)
return Error(LunaException(fallback, cause=e))
return sync_wrapper
return decorator |
@dbrattli if you'd like i can contribute a generic version of the above to the repo |
i'm unsure of how to use async functions and @effect.result. The below results in tons of typehints
The text was updated successfully, but these errors were encountered: