How to Build a Mock ML Pipeline with Prefect in Python

Create a lightweight Prefect flow with mock preprocessing, training, and evaluation tasks to prototype an ML pipeline end-to-end.

Medium Python 3.9+ Aug 9, 2026 ML engineering pipelines 12 views 0 copies

Requires third-party packages — install first
pip install prefect

Python code

33 lines
Python 3.9+
from prefect import task, flow
from datetime import datetime


@task
def preprocess_data(raw_value: float) -> float:
    """Mock preprocessing: normalize the input value."""
    return raw_value / 100.0


@task
def train_model(features: float) -> dict:
    """Mock training: return a fake model artifact."""
    return {"model_type": "linear", "trained_on": datetime.now().isoformat(), "metric": features * 0.95}


@task
def evaluate_model(model: dict) -> str:
    """Mock evaluation: produce a short report."""
    return f"Model {model['model_type']} scored {model['metric']:.2f} (trained {model['trained_on']})"


@flow(name="mock_ml_pipeline")
def ml_flow(raw_input: float = 42.0):
    processed = preprocess_data(raw_input)
    model = train_model(processed)
    report = evaluate_model(model)
    print(report)
    return report


if __name__ == "__main__":
    ml_flow(42.0)

Output

stdout
Model linear scored 0.40 (trained 2025-03-15T10:30:00.123456)

How it works

This code uses Prefect decorators @task and @flow to turn ordinary Python functions into orchestrated units. Each task encapsulates a stage of an ML pipeline — preprocessing, training, and evaluation — and the flow chains them together by calling the tasks directly. Prefect automatically captures the execution graph, retries, and logging, so you can switch these mock functions with real implementations later. The datetime.now().isoformat() call inside train_model gives a realistic timestamp artifact to mimic actual model metadata.

Common mistakes

  • Forgetting to include `if __name__ == '__main__':` when running the flow as a script
  • Assuming Prefect tasks are plain Python functions — they return `PrefectFuture` objects outside a flow context
  • Not pinning the Prefect version in requirements, causing API breakage between 2.x and 3.x

Variations

  1. Use `@task(retries=2)` to add automatic retry logic to a real model training call
  2. Wrap the flow in `with Flow('name') as flow:` for Prefect 1.x syntax

Real-world use cases

  • Prototyping a data science pipeline before investing in heavy training infrastructure, letting you validate the orchestration logic quickly.
  • Running scheduled batch inference jobs where each step (preprocess, predict, evaluate) is a Prefect task with retries and logging.
  • Stubbing external services like model registries or feature stores during integration tests of your pipeline code.

Sponsored

Run locally

This sample needs third-party packages, so it cannot run in the browser IDE. Copy the code above, install the packages shown at the top, then run it in your own Python environment.

More from ML engineering pipelines

Related tutorials and quizzes for this topic.