Wurzel Executor¶
This section documents the BaseStepExecutor — the core execution environment
used by Wurzel to run typed steps. It covers the typical usage patterns,
environment encapsulation, middleware support, and examples.
Overview¶
BaseStepExecutor is responsible for:
- Loading inputs (from memory or disk) and converting them to the step's input models.
- Running the step's
run()function in a controlled context. - Saving outputs to disk using the step's output model if an output path is provided.
- Optionally wrapping execution with a chain of middlewares that can observe or modify execution, inputs, and outputs.
The executor is designed to enforce strong typing and to provide helpful logging and error reporting when contracts fail.
Usage¶
Basic usage as a context manager:
from pathlib import Path
from wurzel.core import NoSettings, TypedStep
from wurzel.datacontract.common import MarkdownDataContract
from wurzel.executors.base_executor import BaseStepExecutor
class MyStep(TypedStep[NoSettings, None, MarkdownDataContract]):
def run(self, inpt: None) -> MarkdownDataContract:
return MarkdownDataContract(md="# OK", keywords="ok", url="memory://ok")
with BaseStepExecutor() as exc:
results = exc(MyStep, None, Path("output"))
Running the executor with middlewares by name:
from wurzel.executors.base_executor import BaseStepExecutor
with BaseStepExecutor(middlewares=["prometheus"]) as exc:
pass
Or provide middleware instances directly:
from wurzel.executors.base_executor import BaseStepExecutor
from wurzel.executors.middlewares.base import BaseMiddleware
class NoopMiddleware(BaseMiddleware):
def __call__(self, call_next, step_cls, inputs, output_dir):
return call_next(step_cls, inputs, output_dir)
with BaseStepExecutor(middlewares=[NoopMiddleware()]) as exc:
pass
Environment encapsulation¶
When a step defines a settings dataclass (via the step's settings_class),
BaseStepExecutor can automatically build those settings from environment
variables. The executor provides an encapsulation context manager that will
set the relevant environment variables before running the step and restore the
previous environment afterward.
This encapsulation allows tests and runs to provide step-specific settings via environment variables without permanently mutating the process environment.
By default, the executor encapsulates settings; pass dont_encapsulate=True to
disable this behavior.
Middleware support¶
See executor/middlewares.md for details on how to enable, write and use
middlewares.
Error handling and logging¶
- Contract validation errors raised by Pydantic will be translated into
ContractFailedException. - Unexpected errors during execution will be wrapped in
StepFailedwith additional context. - The executor integrates with the project's logging helpers to record uncaught exceptions.
Notes and best practices¶
- The executor will try to sort outputs (for deterministic comparisons) when sensible — if sorting is not possible it will log a warning and continue.
- Use the middleware system to add cross-cutting concerns (metrics, timing, caching, retries) without modifying step logic.