How to Mock a Kubeflow Pipeline in Python
Build a minimal in-memory mock of a Kubeflow pipeline DAG using dataclasses and OrderedDict to chain component functions.
Python code
48 linesfrom typing import Dict, Any
from dataclasses import dataclass, field
from collections import OrderedDict
@dataclass
class KubeflowPipelineMock:
"""A minimal mock of a Kubeflow pipeline DAG."""
name: str
components: OrderedDict[str, callable] = field(default_factory=OrderedDict)
def add_component(self, name: str, func: callable) -> "KubeflowPipelineMock":
"""Register a component (function) in the pipeline."""
self.components[name] = func
return self
def execute(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
"""Run the pipeline, passing outputs as inputs to the next stage."""
data = dict(inputs)
for comp_name, comp_func in self.components.items():
result = comp_func(data)
data.update(result)
print(f"[{comp_name}] -> {list(result.keys())}")
return data
def load_step(context: Dict[str, Any]) -> Dict[str, Any]:
return {"loaded": context.get("raw", "default")}
def transform_step(context: Dict[str, Any]) -> Dict[str, Any]:
return {"transformed": context["loaded"].upper()}
def save_step(context: Dict[str, Any]) -> Dict[str, Any]:
return {"saved": f"final: {context['transformed']}"}
if __name__ == "__main__":
pipeline = (
KubeflowPipelineMock(name="sample-dag")
.add_component("load", load_step)
.add_component("transform", transform_step)
.add_component("save", save_step)
)
outputs = pipeline.execute({"raw": "hello world"})
print(f"Pipeline '{pipeline.name}' finished.")
print(f"Final outputs: {outputs}")
Output
[load] -> ['loaded']
[transform] -> ['transformed']
[save] -> ['saved']
Pipeline 'sample-dag' finished.
Final outputs: {'raw': 'hello world', 'loaded': 'hello world', 'transformed': 'HELLO WORLD', 'saved': 'final: HELLO WORLD'}
How it works
The KubeflowPipelineMock class uses a dataclass to store the pipeline name and an OrderedDict that preserves component registration order. Each component is a plain function that takes a dictionary context and returns a dictionary of new outputs. The execute method iterates through components in order, passing the accumulated data as input and merging returned keys back into the shared context. load_step uses .get() for safe default handling, while transform_step and save_step assume earlier keys exist, mirroring real pipeline dependencies.
Common mistakes
- Forgetting that components receive the full accumulating context, not just their own inputs
- Using a regular dict instead of OrderedDict, which can reorder components in older Python versions
- Not handling missing keys when a component depends on a previous output
Variations
- Use a list of (name, func) tuples instead of OrderedDict for a simpler definition
- Wrap real Kubeflow component builders (e.g., from `kfp.dsl`) inside these mock functions for offline testing
Real-world use cases
- Testing ML pipeline logic locally without a running Kubeflow cluster or Kubernetes dependencies
- Rapid prototyping of new data processing steps before containerizing them as Kubeflow components
- Writing unit tests that verify data flows through feature engineering, training, and evaluation stages in sequence
Sponsored
More from ML engineering pipelines
- Bayesian Optimization in Python: A Simplified Mock Implementation medium
- Build a Data Helper Class in Python for ML Pipelines easy
- Build a Mock Random Forest Classifier in Python easy
- Champion Challenger Deployment Mock in Python easy
- Compare Model A vs Model B Metrics in Python easy
- Create a Minimal Great Expectations Suite Mock in Python easy
Keep learning
Related tutorials and quizzes for this topic.