Pure Python

Flyte 2 introduces a new way of writing workflows that is based on pure Python, removing the constraints of a domain-specific language (DSL) and enabling full use of Python’s capabilities.

From @workflow DSL to pure Python

Flyte 1 Flyte 2
@workflow-decorated functions are constrained to a subset of Python for defining a static directed acyclic graph (DAG) of tasks. No more @workflow decorator: Everything is a @env.task, so your top-level “workflow” is simply a task that calls other tasks.
@task-decorated functions could leverage the full power of Python, but only within individual container executions. @env.tasks can call other @env.tasks and be used to construct workflows with dynamic structures using loops, conditionals, try/except, and any Python construct anywhere.
Workflows were compiled into static DAGs at registration time, with tasks as the nodes and the DSL defining the structure. Workflows are simply tasks that call other tasks. Compile-time safety will be available in the future as compiled_task.
Flyte 1Flyte 2
flyte_1.py
import flytekit

image = flytekit.ImageSpec(
    name="hello-world-image",
    packages=["requests"],
)

@flytekit.task(container_image=image)
def mean(data: list[float]) -> float:
    return sum(list) / len(list)

@flytekit.workflow
def main(data: list[float]) -> float:
    output = mean(data)

    # ❌ performing trivial operations in a workflow is not allowed
    # output = output / 100

    # ❌ if/else is not allowed
    # if output < 0:
    #     raise ValueError("Output cannot be negative")

    return output
flyte_2.py
import flyte

env = flyte.TaskEnvironment(
    "hello_world",
    image=flyte.Image.from_debian_base().with_pip_packages("requests"),
)

@env.task
def mean(data: list[float]) -> float:
    return sum(data) / len(data)

@env.task
def main(data: list[float]) -> float:
    output = mean(data)

    # ✅ performing trivial operations in a workflow is allowed
    output = output / 100

    # ✅ if/else is allowed
    if output < 0:
        raise ValueError("Output cannot be negative")

    return output

These fundamental changes bring several transformative benefits:

  • Flexibility: Harness the complete Python language for workflow definition, including all control flow constructs previously forbidden in workflows.
  • Dynamic workflows: Create workflows that adapt to runtime conditions, handle variable data structures, and make decisions based on intermediate results.
  • Natural error handling: Use standard Python try/except patterns throughout your workflows, making them more robust and easier to debug.
  • Intuitive composability: Build complex workflows by naturally composing Python functions, following familiar patterns that any Python developer understands.