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

Improve error message when omitting task kwarg in workflows #1921

Merged
merged 4 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion flytekit/core/promise.py
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,18 @@
)
is_optional = True
if not is_optional:
raise _user_exceptions.FlyteAssertion("Input was not specified for: {} of type {}".format(k, var.type))
from flytekit.core.base_task import Task

Check warning on line 919 in flytekit/core/promise.py

View check run for this annotation

Codecov / codecov/patch

flytekit/core/promise.py#L919

Added line #L919 was not covered by tests
pingsutw marked this conversation as resolved.
Show resolved Hide resolved

error_msg = f"Input {k} of type {interface.inputs[k]} was not specified for function {entity.name}"

Check warning on line 921 in flytekit/core/promise.py

View check run for this annotation

Codecov / codecov/patch

flytekit/core/promise.py#L921

Added line #L921 was not covered by tests

_, _default = interface.inputs_with_defaults[k]

Check warning on line 923 in flytekit/core/promise.py

View check run for this annotation

Codecov / codecov/patch

flytekit/core/promise.py#L923

Added line #L923 was not covered by tests
if isinstance(entity, Task) and _default is not None:
error_msg += (

Check warning on line 925 in flytekit/core/promise.py

View check run for this annotation

Codecov / codecov/patch

flytekit/core/promise.py#L925

Added line #L925 was not covered by tests
". Flyte workflow syntax is a domain-specific language (DSL) for building execution graphs which "
"supports a subset of Python’s semantics. When calling tasks, all kwargs have to be provided."
)

raise _user_exceptions.FlyteAssertion(error_msg)

Check warning on line 930 in flytekit/core/promise.py

View check run for this annotation

Codecov / codecov/patch

flytekit/core/promise.py#L930

Added line #L930 was not covered by tests
Copy link
Member Author

@fg91 fg91 Oct 26, 2023

Choose a reason for hiding this comment

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

In the review, it would be good to think whether the if statement if isinstance(entity, Task) and _default is not None: is not covering cases where this error message should be added or does cover cases where it shouldn't be added.

I tested the following:

@task
def foo(bar: int = 1) -> int:  # default value that doesn't work
    return bar

@workflow
def wf() -> int:
    return foo()
flytekit.exceptions.user.FlyteAssertion: Error encountered while executing 'wf':
  Input bar of type <FlyteLiteral simple: INTEGER> was not specified for function test.foo.
  Flyte workflow syntax is a domain-specific language (DSL) for building execution graphs which supports a subset of Python’s semantics. When calling tasks, all kwargs have to be provided.
@task
def foo(bar: int) -> int:  # No default value
    return bar

@workflow
def wf() -> int:
    return foo()
flytekit.exceptions.user.FlyteAssertion: Error encountered while executing 'wf':
  Input bar of type <FlyteLiteral simple: INTEGER> was not specified for function test.foo

The issue is not a limitation of DSL vs python but actually no value provided for the kwarg.

@task
def foo(bar: int) -> int:
    return bar

@workflow
def sub_wf(bar: int=1) -> int:
    return foo(bar=bar)

@workflow
def wf() -> int:
    return sub_wf()

No error, as expected.

@task
def foo(bar: int) -> int:
    return bar

@workflow
def sub_wf(bar: int) -> int:   # no default value
    return foo(bar=bar)

@workflow
def wf() -> int:
    return sub_wf()
flytekit.exceptions.user.FlyteAssertion: Error encountered while executing 'wf':
  Encountered error while executing workflow 'sub_wf':
  Input bar of type <FlyteLiteral simple: INTEGER> was not specified for function sub_wf
  1. Now with dynamic
@task
def foo(bar: int) -> int:
    return bar

@dynamic
def sub_wf(bar: int) -> int:  # no default value
    return foo(bar=bar)

@workflow
def wf() -> int:
    return sub_wf()
flytekit.exceptions.user.FlyteAssertion: Error encountered while executing 'wf':
  Input bar of type <FlyteLiteral simple: INTEGER> was not specified for function test.sub_wf
@task
def foo(bar: int) -> int:
    return bar

@dynamic
def sub_wf(bar: int=1) -> int:   # default value that doesn't work
    return foo(bar=bar)

@workflow
def wf() -> int:
    return sub_wf()
flytekit.exceptions.user.FlyteAssertion: Error encountered while executing 'wf':
  Input bar of type <FlyteLiteral simple: INTEGER> was not specified for function test.sub_wf. 
  Flyte workflow syntax is a domain-specific language (DSL) for building execution graphs which supports a subset of Python’s semantics. When calling tasks, all kwargs have to be provided.

Copy link
Member

Choose a reason for hiding this comment

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

would it be better to show the python type in the error message? like

Input bar of type [int] was not specified for function test.

we can get the python type from interface.inputs[k]

Copy link
Member Author

Choose a reason for hiding this comment

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

Good call, thanks!

c725eff

else:
continue
v = kwargs[k]
Expand Down
4 changes: 2 additions & 2 deletions tests/flytekit/unit/core/test_references.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ def test_lps(resource_type):
with context_manager.FlyteContextManager.with_context(ctx.with_new_compilation_state()) as ctx:
with pytest.raises(Exception) as e:
ref_entity()
assert "Input was not specified" in f"{e}"
assert "was not specified for function" in f"{e}"

output = ref_entity(a="hello", b=3)
assert isinstance(output, VoidPromise)
Expand Down Expand Up @@ -321,7 +321,7 @@ def test_ref_sub_wf():
with context_manager.FlyteContextManager.with_context(ctx.with_new_compilation_state()) as ctx:
with pytest.raises(Exception) as e:
ref_entity()
assert "Input was not specified" in f"{e}"
assert "was not specified for function" in f"{e}"

output = ref_entity(a="hello", b=3)
assert isinstance(output, VoidPromise)
Expand Down
Loading