-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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 typing of task decorator for retry_condition_fn argument #16621
base: main
Are you sure you want to change the base?
Fix typing of task decorator for retry_condition_fn argument #16621
Conversation
refresh_cache: Optional[bool] = None, | ||
on_completion: Optional[list[StateHookCallable]] = None, | ||
on_failure: Optional[list[StateHookCallable]] = None, | ||
retry_condition_fn: Optional[Callable[[Task[P, R], TaskRun, State], bool]] = None, |
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.
retry_condition_fn: Optional[Callable[[Task[P, R], TaskRun, State], bool]] = None, | |
retry_condition_fn: Optional[Callable[[Task[P, R], TaskRun, State], bool]] = None, |
Note this previously was Task[P, Any]
but now has R
because it should exactly match. The overload above now matches first when None
is given (or default is used).
@@ -1634,7 +1634,43 @@ def task( | |||
refresh_cache: Optional[bool] = None, | |||
on_completion: Optional[list[StateHookCallable]] = None, | |||
on_failure: Optional[list[StateHookCallable]] = None, | |||
retry_condition_fn: Optional[Callable[[Task[P, Any], TaskRun, State], bool]] = None, | |||
retry_condition_fn: Literal[None] = None, |
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.
This is the new thing that matches first when it is None and doesn't interact with returned P
and R
.
- case: prefect_task_decorator_no_args | ||
main: | | ||
from prefect import task | ||
@task | ||
def foo(bar: str) -> int: | ||
return 42 | ||
reveal_type(foo) | ||
out: "main:5: note: Revealed type is \"\ | ||
prefect.tasks.Task[[bar: builtins.str], builtins.int]\ | ||
\"" |
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.
Works on main branch
- case: prefect_task_decorator_call_with_no_args | ||
main: | | ||
from prefect import task | ||
@task() | ||
def foo(bar: str) -> int: | ||
return 42 | ||
reveal_type(foo) | ||
out: "main:5: note: Revealed type is \"\ | ||
prefect.tasks.Task[[bar: builtins.str], builtins.int]\ | ||
\"" | ||
|
||
- case: prefect_task_decorator_with_name_arg | ||
main: | | ||
from prefect import task | ||
@task(name="bar") | ||
def foo(bar: str) -> int: | ||
return 42 | ||
reveal_type(foo) | ||
out: "main:5: note: Revealed type is \"\ | ||
prefect.tasks.Task[[bar: builtins.str], builtins.int]\ | ||
\"" | ||
|
||
- case: prefect_task_decorator_with_retry_condition_fn_as_none_arg | ||
main: | | ||
from prefect.tasks import task | ||
@task(retry_condition_fn=None) | ||
def foo(bar: str) -> int: | ||
return 42 | ||
reveal_type(foo) | ||
out: "main:5: note: Revealed type is \"\ | ||
prefect.tasks.Task[[bar: builtins.str], builtins.int]\ | ||
\"" |
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.
These 3 all fail on main branch
CodSpeed Performance ReportMerging #16621 will not alter performanceComparing Summary
|
- case: prefect_task_decorator_with_retry_condition_fn_arg | ||
main: | | ||
from prefect.tasks import P, R, Task, task | ||
from prefect.client.schemas import TaskRun | ||
from prefect.states import State | ||
def retry_condition_fn(task: Task[P, R], task_run: TaskRun, state: State) -> bool: | ||
return False | ||
@task(retry_condition_fn=retry_condition_fn) | ||
def foo(bar: str) -> int: | ||
return 42 | ||
reveal_type(foo) | ||
out: "main:9: note: Revealed type is \"\ | ||
prefect.tasks.Task[[bar: builtins.str], builtins.int]\ | ||
\"" |
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.
Works on main branch
hi @peterbygrave - thanks for the PR! can you provide your version of for example, I am not seeing from typing import Any, reveal_type
from prefect import Task, task
from prefect.cache_policies import NONE
from prefect.client.schemas.objects import State, TaskRun
def state_hook(task: Task[Any, Any], task_run: TaskRun, state: State):
print(f"Task run {task_run.name!r} from {task.name!r} entered state {state.name!r}")
@task(retries=1, persist_result=False, on_completion=[state_hook])
def identity(x: int) -> int:
return x
@task(persist_result=False)
def identity_no_cache(x: int) -> int:
return x
@task(cache_policy=NONE)
def returns_something(x: int) -> int:
return x
@task(
name="conditionally_retries",
retry_condition_fn=lambda task, task_run, state: True,
retry_delay_seconds=[1, 2],
)
def conditionally_retries(x: int) -> int:
return x
@task
def also_returns_something(x: int) -> int:
return x
if __name__ == "__main__":
value = returns_something(1)
something = identity(value)
something_else = identity_no_cache(value)
other_value = also_returns_something(1)
result = conditionally_retries(1)
reveal_type(value)
reveal_type(something)
reveal_type(something_else)
reveal_type(other_value)
reveal_type(result) when I checkout your branch, this |
We are just doing our v2 to v3 migration so first saw this on v3.1.11, but has issues on main branch. The code example I have are in the tests. Its all isolated to retry_condition_fn because it is capable of narrowing the
So the
I'm not sure if that would need to be in additional or replacement of. If replacement it would probably exclude the ability to have stronger type checking - in that one wouldn't be able to check you are handling a task with the right args and return type (if you wanted to depend on them). |
In migrating to prefect v3, we are seeing issues with mypy checking of the task decorators. For example when making the decorator a call e.g.
@task()
or@task(name="foo")
you end up with:I found that it was the typing of
retry_condition_fn
that flakes out because the input typing should connected to the return type, but nothing can be inferred because nothing was given.In this PR I add an overload to differentiate between None and an actual function is passed.
Checklist
<link to issue>
"mint.json
.