-
Notifications
You must be signed in to change notification settings - Fork 305
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
fix: add FlyteValueException handling and clean up exit_handler calls #3036
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: Vincent <0426vincent@gmail.com>
Code Review Agent Run #a5368cActionable Suggestions - 1
Review Details
|
@@ -168,7 +168,7 @@ def execute(self, *args, **kwargs): | |||
|
|||
write_example_notebook(task_function=self.task_function, notebook_dir=self.notebook_dir) | |||
|
|||
return exit_handler( | |||
exit_handler( |
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.
Remove the return
for both Jupyter and VS Code. I'm not sure if this will cause any side effects. If not removed, native_output will receive the mock function return from execute
, which will then throw an error as the output interface is empty.
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.
We cannot remove return
here. Where did you see the error?
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.
Hi @pingsutw
flytekit/flytekit/core/base_task.py
Lines 779 to 783 in ea17a4d
if native_outputs is not None and len(list(self._outputs_interface.keys())) == 0: | |
raise FlyteValueException( | |
native_outputs, | |
f"Interface has {len(self.python_interface.outputs)} outputs.", | |
) |
the following tests will fail as they would return the mock handler but the output interface expects to have 0 outputs
pytest -sv tests/flytekit/unit/interactive/test_flyteinteractive_vscode.py::test_vscode_remote_execution
flytekit/tests/flytekit/unit/interactive/test_flyteinteractive_vscode.py
Lines 139 to 142 in 9c2caa1
@task | |
@vscode | |
def t(): | |
return |
this one should fail, too
flytekit/plugins/flytekit-flyteinteractive/tests/test_flyteinteractive_jupyter.py
Lines 38 to 41 in 9c2caa1
@task | |
@jupyter | |
def t(): | |
return |
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.
ah, you can add return type to that function.
@task
@vscode
def t() -> str:
return "hello"
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.
Adding -> str
might require modifying the return value of exit_handler() as t() may be overridden by the decorator?
mock.patch(
"flytekit.interactive.vscode_lib.decorator.exit_handler",
return_value="Hello, world!",
However, this will further lead to other errors, which I don't think is solvable as @VScode may not always return exit_handler(). Thanks.
full error log
vscode_patches = (, , <MagicMock...10240'>, , , ...)
mock_local_execution =
def test_vscode_local_execution(vscode_patches, mock_local_execution):
(
mock_process,
mock_prepare_interactive_python,
mock_exit_handler,
mock_download_vscode,
mock_signal,
mock_prepare_resume_task_python,
mock_prepare_launch_json,
) = vscode_patches
@task
@vscode
def t() -> str:
return
@workflow
def wf():
t()
wf()
tests/flytekit/unit/interactive/test_flyteinteractive_vscode.py:149:
flytekit/core/workflow.py:308: in call
raise exc
flytekit/core/workflow.py:301: in call
return flyte_entity_call_handler(self, *args, **input_kwargs)
flytekit/core/promise.py:1526: in flyte_entity_call_handler
return cast(LocallyExecutable, entity).local_execute(ctx, **kwargs)
flytekit/core/workflow.py:327: in local_execute
function_outputs = self.execute(**kwargs_literals)
flytekit/core/workflow.py:838: in execute
return self._workflow_function(**kwargs)
tests/flytekit/unit/interactive/test_flyteinteractive_vscode.py:147: in wf
t()
flytekit/core/base_task.py:365: in call
return flyte_entity_call_handler(self, *args, **kwargs) # type: ignore
flytekit/core/promise.py:1526: in flyte_entity_call_handler
return cast(LocallyExecutable, entity).local_execute(ctx, **kwargs)
flytekit/core/base_task.py:345: in local_execute
outputs_literal_map = self.sandbox_execute(ctx, input_literal_map)
flytekit/core/base_task.py:422: in sandbox_execute
return self.dispatch_execute(ctx, input_literal_map)
flytekit/core/base_task.py:787: in dispatch_execute
literals_map, native_outputs_as_map = run_sync(
flytekit/utils/asyn.py:106: in run_sync
return self._runner_map[name].run(coro)
flytekit/utils/asyn.py:85: in run
res = fut.result(None)
/opt/homebrew/Cellar/python@3.12/3.12.8/Frameworks/Python.framework/Versions/3.12/lib/python3.12/concurrent/futures/_base.py:456: in result
return self.__get_result()
/opt/homebrew/Cellar/python@3.12/3.12.8/Frameworks/Python.framework/Versions/3.12/lib/python3.12/concurrent/futures/_base.py:401: in __get_result
raise self._exception
flytekit/core/base_task.py:656: in _output_to_literal_map
raise e
flytekit/core/type_engine.py:1389: in async_to_literal
cls.to_literal_checks(python_val, python_type, expected)
cls = <class 'flytekit.core.type_engine.TypeEngine'>, python_val = None, python_type = <class 'str'>
expected = Flyte Serialized object (LiteralType):
simple: 3
@classmethod
def to_literal_checks(cls, python_val: typing.Any, python_type: Type[T], expected: LiteralType):
from flytekit.core.promise import VoidPromise
if isinstance(python_val, VoidPromise):
raise AssertionError(
f"Outputs of a non-output producing task {python_val.task_name} cannot be passed to another task."
)
if isinstance(python_val, tuple):
raise AssertionError(
"Tuples are not a supported type for individual values in Flyte - got a tuple -"
f" {python_val}. If using named tuple in an inner task, please, de-reference the"
"actual attribute that you want to use. For example, in NamedTuple('OP', x=int) then"
"return v.x, instead of v, even if this has a single element"
)
if (
(python_val is None and python_type != type(None))
and expected
and expected.union_type is None
and python_type is not Any
):
raise TypeTransformerFailedError(f"Python value cannot be None, expected {python_type}/{expected}")
E flytekit.core.type_engine.TypeTransformerFailedError: Failed to convert outputs of task 'channelexec.test_flyteinteractive_vscode.t' at position 0.
E Failed to convert type <class 'NoneType'> to type <class 'str'>.
E Error Message: Python value cannot be None, expected <class 'str'>/Flyte Serialized object (LiteralType):
E simple: 3.
flytekit/core/type_engine.py:1330: TypeTransformerFailedError
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.
Why not just mock the return value to None in the unit test? (vscode_patches
function of test_flyteinteractive_vscode.py
)
Changelist by BitoThis pull request implements the following key changes.
|
@@ -456,7 +456,7 @@ def execute(self, *args, **kwargs): | |||
# 5. Prepare the launch.json | |||
prepare_launch_json() | |||
|
|||
return exit_handler( | |||
exit_handler( |
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.
The exit_handler
function returns a value but the return value is not being captured. Consider capturing the return value or handling it appropriately. A similar issue was also found in plugins/flytekit-flyteinteractive/flytekitplugins/flyteinteractive/jupyter_lib/decorator.py (line 171).
Code suggestion
Check the AI-generated fix before applying
exit_handler( | |
return exit_handler( |
Code Review Run #a5368c
Is this a valid issue, or was it incorrectly flagged by the Agent?
- it was incorrectly flagged
Signed-off-by: Vincent <0426vincent@gmail.com>
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #3036 +/- ##
==========================================
- Coverage 82.79% 79.54% -3.26%
==========================================
Files 3 202 +199
Lines 186 21359 +21173
Branches 0 2746 +2746
==========================================
+ Hits 154 16989 +16835
- Misses 32 3602 +3570
- Partials 0 768 +768 ☔ View full report in Codecov by Sentry. |
Code Review Agent Run #0101b5Actionable Suggestions - 0Additional Suggestions - 1
Review Details
|
…ler return value Signed-off-by: Vincent <0426vincent@gmail.com>
Code Review Agent Run #f8b810Actionable Suggestions - 0Review Details
|
Signed-off-by: Vincent <0426vincent@gmail.com>
Signed-off-by: Vincent <0426vincent@gmail.com>
Code Review Agent Run #d37b87Actionable Suggestions - 0Review Details
|
@vincent0426 Can you add some unit tests to make sure running the task/workflow without specifying output while returning a non-None value would throw an error? Also, running with |
Signed-off-by: Vincent <0426vincent@gmail.com>
Code Review Agent Run #dd9258Actionable Suggestions - 0Review Details
|
Tracking issue
Why are the changes needed?
Currently, if a task returns a value but does not specify a return type, the return value will be empty instead of raising an error.
It is expected to raise an error if a function returns a value but no return type is specified.
This should throw an error, but it doesn't
pyflyte run example.py greeting_length --greeting="hello"
What changes were proposed in this pull request?
Add conditions check to throw an error if
native_outputs
have value but no output interface is specifiedHow was this patch tested?
Setup process
pyflyte run example.py greeting_length --greeting="hello"
Screenshots
Check all the applicable boxes
Related PRs
Docs link
Summary by Bito
Implementation of enhanced error handling for tasks with undefined/unspecified return types, introducing FlyteValueException for validation of native outputs. Added comprehensive test cases covering regular returns, optional types, and error scenarios. Enhanced test coverage for task return type handling mechanisms and improved validation in test files to prevent silent failures. Optimized exit_handler calls in VSCode and Jupyter environments for better type safety.Unit tests added: True
Estimated effort to review (1-5, lower is better): 1