-
Notifications
You must be signed in to change notification settings - Fork 1
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
chore: improve error output when call unwrap_or_return on a function … #80
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ def expected_error(value: str, called_from: Union[str, None] = None, escape: boo | |
f"This exception wraps the following result -> Result[status: failure | value: {value}]" | ||
f"\nIf you want to handle this error and return a Failure, please use early_return decorator on your function{called_from}." | ||
f"\nMore info about how to use unwrap_or_return in combination with @early_return decorator on https://alice-biometrics.github.io/meiga/usage/result/#unwrap_or_return" | ||
f"\nUse @async_early_return if your are calling from an async function." | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've tried to guess if caller is a regular function or an async one with something like the following: import inspect
from typing import Union
class WaitingForEarlyReturn(Exception):
result: 'AnyResult' # Replace with the actual class/type if AnyResult is not defined
called_from: Union[str, None]
called_from_coroutine: bool = False
def __init__(self, result: 'AnyResult') -> None:
self.result = result
try:
# Get the stack frame
stack = inspect.stack()[2]
frame = stack.frame
function_name = frame.f_code.co_name # Get the name of the function
filename = stack.filename.split("/")[-1]
# We can't retrieve the actual function object, so we check by name
self.called_from_coroutine = frame.f_globals.get(function_name) and inspect.iscoroutinefunction(frame.f_globals[function_name])
# Create a descriptive string for where this was called from
if self.called_from_coroutine:
self.called_from = f"{function_name} (async) on {filename}"
else:
self.called_from = f"{function_name} on {filename}"
except Exception: # noqa
self.called_from = None
# Call the base class initializer
Exception.__init__(self) But, I think is not possible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know why you say it doesn't work 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because This is because If you modify the test, you'll notice the code never pass through @pytest.mark.asyncio
async def should_log_hint_when_called_async_from_class_function_and_not_early_return(self):
class MyClass:
async def execute(self) -> AnyResult:
result = Failure(Error())
result.unwrap_or_return()
return isSuccess
with pytest.raises(
WaitingForEarlyReturn,
match=expected_error(
"Error",
called_from="execute (async) on test_waiting_for_early_return.py", # <-------- THIS
escape=True,
),
):
await MyClass().execute() There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I found a way (not very elegant). Check my last commit |
||
) | ||
if escape: | ||
return re.escape(text) # necessary to match on pytest.raises contextmanager | ||
|
@@ -84,3 +85,38 @@ def execute(self) -> AnyResult: | |
), | ||
): | ||
MyClass().execute() | ||
|
||
@pytest.mark.asyncio | ||
async def should_log_hint_when_called_async_from_class_function_and_not_early_return(self): | ||
class MyClass: | ||
async def execute(self) -> AnyResult: | ||
result = Failure(Error()) | ||
result.unwrap_or_return() | ||
return isSuccess | ||
|
||
with pytest.raises( | ||
WaitingForEarlyReturn, | ||
match=expected_error( | ||
"Error", | ||
called_from="execute (async) on test_waiting_for_early_return.py", | ||
escape=True, | ||
), | ||
): | ||
await MyClass().execute() | ||
|
||
@pytest.mark.asyncio | ||
async def should_log_hint_when_called_async_from_function_and_not_early_return(self): | ||
async def execute() -> AnyResult: | ||
result = Failure(Error()) | ||
result.unwrap_or_return() | ||
return isSuccess | ||
|
||
with pytest.raises( | ||
WaitingForEarlyReturn, | ||
match=expected_error( | ||
"Error", | ||
called_from="execute (async) on test_waiting_for_early_return.py", | ||
escape=True, | ||
), | ||
): | ||
await execute() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this depends on some ruff configuration. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New versions of ruff handle things differently to older versions.