<@ULVA73B9P> When testing flows within a `prefect_...
# ask-marvin
v
@Marvin When testing flows within a
prefect_test_harness
context, by default, flows executions return the return value of the flow. How can I get the flow execution to return a
State
object instead ?
m
thought for 26.5 seconds
When testing flows within a
prefect_test_harness
context, you can get the flow execution to return a
State
object by setting the
return_state=True
parameter when calling the flow. Here's an example:
Copy code
python
from prefect import flow

@flow
def my_test_flow():
    return "Hello"

with prefect_test_harness():
    state = my_test_flow(return_state=True)  # Returns State object instead of "Hello"
    assert state.type == "COMPLETED"
    assert state.result() == "Hello"  # Access the actual return value
When
return_state=True
is set, you'll get back a
State
object that contains metadata about the flow run, including its status and result. You can then: - Check the state type using
state.type
- Access the actual flow return value using
state.result()
- Inspect other state attributes like timestamps and run IDs This is particularly useful when you need to test not just the flow's output, but also its execution state and metadata.
v
@Marvin Can I access tasks results from this State object ?
m
thought for 115.4 seconds
Yes, you can access task results from a flow's State object, but you'll need to ensure you capture the task states during flow execution. Here's how you can do it:
Copy code
python
from prefect import flow, task
from prefect.states import get_state_result

@task
def task_1():
    return "Hello"

@task
def task_2():
    return "World"

@flow
def my_flow():
    # Store task states in a dictionary
    task_states = {}
    task_states["task_1"] = task_1(return_state=True)
    task_states["task_2"] = task_2(return_state=True)
    return task_states

# Run the flow and get states
with prefect_test_harness():
    flow_state = my_flow(return_state=True)
    task_states = flow_state.result()
    
    # Access individual task results
    task_1_result = get_state_result(task_states["task_1"])
    task_2_result = get_state_result(task_states["task_2"])
    
    # Or use the state's result() method directly
    task_1_result = task_states["task_1"].result()
    task_2_result = task_states["task_2"].result()
A few important points: 1. You need to call tasks with
return_state=True
to get their State objects 2. You can access task results either using the
get_state_result()
function or the state's
result()
method 3. The State object contains additional metadata about the task execution, such as: - `state.type`: The type of state (e.g., "COMPLETED", "FAILED") - `state.timestamp`: When the state was created - `state.name`: The name of the state This approach is particularly useful for testing scenarios where you need to verify both the results and the execution state of individual tasks within a flow.
v
@Marvin Is there no way to capture task states without explicitly capturing them the flow code ? In Prefect 1 this was possible from the flow State
m
thought for 57.4 seconds
No, in Prefect 3.x there isn't a built-in way to access task states from a flow's State object without explicitly capturing them in the flow code, unlike in Prefect 1.x. This is a significant architectural change that reflects Prefect 3.x's more streamlined approach to state management. If you need to track task states for testing or monitoring purposes, you'll need to either: 1. Explicitly capture states in your flow code (as shown in the previous example) 2. Use the Prefect API or UI to query task runs associated with a flow run 3. Set up state change handlers or observers if you need to monitor task states during execution This is indeed different from Prefect 1.x, where you could access task states directly from the flow state. The change aligns with Prefect 3.x's philosophy of being more explicit and having cleaner abstractions, though it does require a bit more intentional state management in your flow code when you need to track task states.