Repository: PrefectHQ/prefect

Issue:
PIN 16: deprecate Task kwargs that are moving to `Result`
## Use Case
See PIN 16 (PR #2134) for background.

## Solution
Raise DeprecationWarnings upon use of cache_for, cache_validator, cache_key and result_handler kwargs on task initialization. (These are either directly or effectively being moved to the `Result` class during this PIN.)




## Alternatives
*Please describe any alternatives you've considered, even if you've dismissed them*



Discussion:

Resolving patch:
diff --git a/src/prefect/core/flow.py b/src/prefect/core/flow.py
--- a/src/prefect/core/flow.py
+++ b/src/prefect/core/flow.py
@@ -30,7 +30,7 @@
 import prefect.schedules
 from prefect.core.edge import Edge
 from prefect.core.task import Parameter, Task
-from prefect.engine.result import NoResult
+from prefect.engine.result import NoResult, Result
 from prefect.engine.result_handlers import ResultHandler
 from prefect.environments import Environment
 from prefect.environments.storage import Storage, get_default_storage_class
@@ -114,6 +114,9 @@ def my_task():
         - edges ([Edge], optional): A list of edges between tasks
         - reference_tasks ([Task], optional): A list of tasks that determine the final
             state of a flow
+        - result (Result, optional, RESERVED FOR FUTURE USE): the result instance used to retrieve and store task results during execution
+        - result_handler (ResultHandler, optional, DEPRECATED): the handler to use for
+            retrieving and storing state results during execution
         - state_handlers (Iterable[Callable], optional): A list of state change handlers
             that will be called whenever the flow changes state, providing an
             opportunity to inspect or modify the new state. The handler
@@ -128,9 +131,6 @@ def my_task():
             the flow (e.g., presence of cycles and illegal keys) after adding the edges passed
             in the `edges` argument. Defaults to the value of `eager_edge_validation` in
             your prefect configuration file.
-        - result_handler (ResultHandler, optional): the handler to use for
-            retrieving and storing state results during execution
-
     """
 
     def __init__(
@@ -145,7 +145,8 @@ def __init__(
         state_handlers: List[Callable] = None,
         on_failure: Callable = None,
         validate: bool = None,
-        result_handler: ResultHandler = None,
+        result_handler: Optional[ResultHandler] = None,
+        result: Optional[Result] = None,
     ):
         self._cache = {}  # type: dict
 
@@ -159,6 +160,12 @@ def __init__(
         self.storage = storage
         self.result_handler = result_handler
 
+        if result_handler:
+            warnings.warn(
+                "DEPRECATED: the result_handler Flow option will be deprecated in 0.11.0, and removed in 0.12.0, in favor of the `result` option instead.",
+                UserWarning,
+            )
+
         self.tasks = set()  # type: Set[Task]
         self.edges = set()  # type: Set[Edge]
         self.constants = collections.defaultdict(
diff --git a/src/prefect/core/task.py b/src/prefect/core/task.py
--- a/src/prefect/core/task.py
+++ b/src/prefect/core/task.py
@@ -15,6 +15,7 @@
     Set,
     Tuple,
     Union,
+    Optional,
 )
 
 import prefect
@@ -27,7 +28,8 @@
 
 if TYPE_CHECKING:
     from prefect.core.flow import Flow  # pylint: disable=W0611
-    from prefect.engine.result_handlers import ResultHandler
+    from prefect.engine.result import Result  # pylint: disable=W0611
+    from prefect.engine.result_handlers import ResultHandler  # pylint: disable=W0611
     from prefect.engine.state import State  # pylint: disable=W0611
 
 VAR_KEYWORD = inspect.Parameter.VAR_KEYWORD
@@ -129,21 +131,22 @@ def run(self, x, y):
                 regardless of trigger. By default, this prevents tasks from attempting to use either state or data
                 from tasks that didn't run. If `False`, the task's trigger will be called as normal,
                 with skips considered successes. Defaults to `True`.
-        - cache_for (timedelta, optional): The amount of time to maintain a cache
+        - cache_for (timedelta, optional, DEPRECATED): The amount of time to maintain a cache
             of the outputs of this task.  Useful for situations where the containing Flow
             will be rerun multiple times, but this task doesn't need to be.
-        - cache_validator (Callable, optional): Validator that will determine
+        - cache_validator (Callable, optional, DEPRECATED): Validator that will determine
             whether the cache for this task is still valid (only required if `cache_for`
             is provided; defaults to `prefect.engine.cache_validators.duration_only`)
-        - cache_key (str, optional): if provided, a `cache_key` serves as a unique identifier for this Task's cache, and can
+        - cache_key (str, optional, DEPRECATED): if provided, a `cache_key` serves as a unique identifier for this Task's cache, and can
             be shared across both Tasks _and_ Flows; if not provided, the Task's _name_ will be used if running locally, or the
             Task's database ID if running in Cloud
         - checkpoint (bool, optional): if this Task is successful, whether to
             store its result using the `result_handler` available during the run; Also note that
             checkpointing will only occur locally if `prefect.config.flows.checkpointing` is set to `True`
-        - result_handler (ResultHandler, optional): the handler to use for
+        - result_handler (ResultHandler, optional, DEPRECATED): the handler to use for
             retrieving and storing state results during execution; if not provided, will default to the
             one attached to the Flow
+        - result (Result, optional, RESERVED FOR FUTURE USE): the result instance used to retrieve and store task results during execution
         - state_handlers (Iterable[Callable], optional): A list of state change handlers
             that will be called whenever the task changes state, providing an
             opportunity to inspect or modify the new state. The handler
@@ -179,10 +182,11 @@ def __init__(
         cache_validator: Callable = None,
         cache_key: str = None,
         checkpoint: bool = None,
-        result_handler: "ResultHandler" = None,
+        result_handler: Optional["ResultHandler"] = None,
         state_handlers: List[Callable] = None,
         on_failure: Callable = None,
         log_stdout: bool = False,
+        result: Optional["Result"] = None,
     ):
         self.name = name or type(self).__name__
         self.slug = slug or str(uuid.uuid4())
@@ -248,6 +252,18 @@ def __init__(
         self.checkpoint = checkpoint
         self.result_handler = result_handler
 
+        if cache_for or cache_key or cache_validator:
+            warnings.warn(
+                "DEPRECATED: all cache_* options on a Task will be deprecated in 0.11.0, and removed in 0.12.0; the options will be moved to a Task's prefect.engine.Result object.",
+                UserWarning,
+            )
+
+        if result_handler:
+            warnings.warn(
+                "DEPRECATED: the result_handler Task option will be deprecated in 0.11.0, and removed in 0.12.0, in favor of the `result` option instead.",
+                UserWarning,
+            )
+
         if state_handlers and not isinstance(state_handlers, collections.Sequence):
             raise TypeError("state_handlers should be iterable.")
         self.state_handlers = state_handlers or []


Test patch:
diff --git a/tests/core/test_flow.py b/tests/core/test_flow.py
--- a/tests/core/test_flow.py
+++ b/tests/core/test_flow.py
@@ -2637,3 +2637,10 @@ def slow_fn():
     assert state.is_failed()
     assert isinstance(state.result[slow_fn], TimedOut)
     assert isinstance(state.result[slow_fn].result, TimeoutError)
+
+
+def test_result_handler_option_shows_deprecation():
+    with pytest.warns(
+        UserWarning, match="the result_handler Flow option will be deprecated*"
+    ):
+        Flow("dummy", result_handler=object())
diff --git a/tests/core/test_task.py b/tests/core/test_task.py
--- a/tests/core/test_task.py
+++ b/tests/core/test_task.py
@@ -594,3 +594,27 @@ def test_task_check_mapped_args_are_subscriptable_in_advance(self):
         with pytest.raises(TypeError):
             with Flow(name="test") as f:
                 res = t.map({1, 2, 3, 4})
+
+
+def test_cache_options_show_deprecation():
+    with pytest.warns(
+        UserWarning, match="all cache_\* options on a Task will be deprecated*"
+    ):
+        Task(cache_for=object())
+
+    with pytest.warns(
+        UserWarning, match="all cache_\* options on a Task will be deprecated*"
+    ):
+        Task(cache_validator=object())
+
+    with pytest.warns(
+        UserWarning, match="all cache_\* options on a Task will be deprecated*"
+    ):
+        Task(cache_key=object())
+
+
+def test_result_handler_option_shows_deprecation():
+    with pytest.warns(
+        UserWarning, match="the result_handler Task option will be deprecated*"
+    ):
+        Task(result_handler=object())