Processing pipelines#
pyramids.processing turns existing Dataset / FeatureCollection operations into named, self-describing
tools that can be chained into a serializable pipeline and run (batched) over one or many inputs — a
QGIS-Processing-style workflow layer built on the ops pyramids already owns.
The pieces:
- a registry of named tools, each with a parameter schema and an input type (
DatasetvsFeatureCollection); - a
Pipeline— an ordered chain of(tool, parameters)steps, serializable to a portable YAML "model" file; - a batch
runwith an error policy and optional process-pool parallelism; - a provenance record per run (tool, parameters, timing) that can re-emit the exact pipeline that produced an output.
v1 tool allowlist#
v1 ships a curated, real-signature allowlist (see ADR 0007 for why it
is hand-written rather than introspected). List it with pyramids tools:
| tool | input → output |
|---|---|
slope, aspect, hillshade, focal_mean, focal_std |
Dataset → Array* |
to_crs, resample, fill, sieve |
Dataset → Dataset |
interpolate_to_raster |
FeatureCollection → Dataset |
to_h3, voronoi, quadtree, with_centroid, with_coordinates |
FeatureCollection → FeatureCollection |
* The terrain ops natively return a numpy array; inside a pipeline the runner materializes it back into a
single-band, georeferenced Dataset (carrying the source raster's geotransform/CRS), so the result is writable to
disk and can be chained into a further Dataset step.
The registry is extensible — register a ToolMetadata to add a tool.
Example (Python)#
A cross-type pipeline: interpolate scattered points onto a raster, then compute its slope. interpolate_to_raster
is a FeatureCollection op that returns a Dataset, and slope runs on that Dataset — the runner dispatches each
step to the correct input type automatically.
from pyramids.feature import FeatureCollection
from pyramids.processing import Pipeline, run
gauges = FeatureCollection.read_file("samples/elevation_points.geojson")
pipe = Pipeline([
("interpolate_to_raster", {"column": "elevation", "cell_size": 1000.0}),
("slope", {}),
])
pipe.to_yaml("elevation_slope.yaml") # the portable "model"
result = run(pipe, gauges) # batch over one or many inputs
slope_raster = result.outputs[0] # a georeferenced Dataset (slope array materialized)
print(result.provenance[0].total_seconds) # per-run timing
Example (CLI)#
pyramids tools # list registered tools
pyramids tool interpolate_to_raster # show a tool's parameters
pyramids run elevation_slope.yaml \
--inputs "samples/*.geojson" --out out/ # batch over a glob, write to out/
run writes each output into --out as <source-stem>_<index> (the batch index keeps same-basename inputs from
colliding); existing files in --out are overwritten, so re-running a batch into the same directory replaces the
prior outputs. --on-error skip (default) collects failures and continues, --on-error raise fails fast, and
--parallel (with --max-workers) fans the batch across a process pool (file-path inputs only — GDAL handles
cannot cross process boundaries).
API#
pyramids.processing.Pipeline
#
An ordered, validated chain of geoprocessing steps.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
steps
|
Iterable[tuple[str, dict[str, Any]]]
|
An iterable of |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If any step names an unknown tool or supplies parameters that fail the tool's schema (validation happens here, at construction). |
Source code in src/pyramids/processing/pipeline.py
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | |
steps
property
#
An independent copy of the pipeline's steps.
Returns fresh :class:Step objects with copied parameters dicts, so
mutating the returned steps (or their parameters) never affects the pipeline.
from_dict(data)
classmethod
#
Build a pipeline from a mapping produced by :meth:to_dict.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
dict[str, Any]
|
A mapping with a |
required |
Returns:
| Type | Description |
|---|---|
Pipeline
|
A validated :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/pyramids/processing/pipeline.py
from_yaml(path)
classmethod
#
Read a pipeline from a YAML file written by :meth:to_yaml.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Path to a pipeline YAML file. |
required |
Returns:
| Type | Description |
|---|---|
Pipeline
|
A validated :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the file is not a mapping with a |
Source code in src/pyramids/processing/pipeline.py
to_dict()
#
Return the pipeline as a plain, YAML-ready mapping.
Each step's parameters is copied, and any os.PathLike value is coerced to
a plain string so the mapping is safe to yaml.safe_dump.
Source code in src/pyramids/processing/pipeline.py
to_yaml(path)
#
Write the pipeline to a portable, version-controllable YAML file.
Every step's parameters are re-validated with for_serialization=True first,
so a pipeline carrying a non-serializable value (array / mask / callable /
in-memory object) raises here instead of writing a file that cannot be
loaded back.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Destination |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If any step carries a non-serializable parameter value. |
Source code in src/pyramids/processing/pipeline.py
pyramids.processing.run(pipeline, inputs, *, on_error='skip', out=None, parallel=False, max_workers=None)
#
Run pipeline over inputs and collect the results.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pipeline
|
Pipeline
|
The :class: |
required |
inputs
|
Any
|
A single path/object, a glob string, a list/tuple of those, or a
|
required |
on_error
|
str
|
|
'skip'
|
out
|
str | None
|
Optional output directory; when given, each successful output is
written there as |
None
|
parallel
|
bool
|
When |
False
|
max_workers
|
int | None
|
Worker-process count for |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
RunResult
|
class: |
RunResult
|
written paths in |
|
RunResult
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Exception
|
The first per-item error when |
Source code in src/pyramids/processing/runner.py
pyramids.processing.RunResult
dataclass
#
The outcome of a batch :func:run.
Attributes:
| Name | Type | Description |
|---|---|---|
outputs |
list[Any]
|
The final object produced for each input that succeeded, in input
order. In serial mode these are in-memory |
failures |
list[tuple[Any, Exception]]
|
|
provenance |
list[Provenance]
|
One :class: |
Source code in src/pyramids/processing/runner.py
ok
property
#
Whether every input succeeded (no collected failures).
pyramids.processing.Provenance
dataclass
#
The recorded recipe + timing for one processed input.
Attributes:
| Name | Type | Description |
|---|---|---|
source |
str
|
A label for the input (a path, or a |
steps |
list[StepRecord]
|
The executed :class: |
Source code in src/pyramids/processing/provenance.py
total_seconds
property
#
Total wall-clock time across all steps.
to_pipeline()
#
Re-emit the exact :class:Pipeline that produced the output.
Returns:
| Name | Type | Description |
|---|---|---|
A |
Pipeline
|
class: |
Pipeline
|
through |
Source code in src/pyramids/processing/provenance.py
pyramids.processing.ToolMetadata
dataclass
#
Describe one named, addressable pyramids op.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The tool name used in a pipeline and on the CLI. |
required |
input_type
|
str
|
The object the tool runs on — |
required |
output_type
|
str
|
The object type the tool produces. |
required |
parameters
|
tuple[Parameter, ...]
|
The tool's parameters. |
()
|
description
|
str
|
Human-readable summary. |
''
|
method
|
str | None
|
The method name on the input object; defaults to |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/pyramids/processing/schema.py
method_name
property
#
The method this tool invokes on its input object.
help()
#
Render a multi-line help block describing the tool and its parameters.
Source code in src/pyramids/processing/schema.py
param(name)
#
Return the :class:Parameter named name (or None).
pyramids.processing.Parameter
dataclass
#
Describe a single tool parameter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The keyword-argument name passed to the underlying op. |
required |
parameter_type
|
str
|
One of :data: |
required |
default
|
Any
|
Display-only default shown in |
None
|
optional
|
bool
|
Whether the parameter may be omitted. |
True
|
description
|
str
|
Human-readable help text. |
''
|
choices
|
tuple[str, ...] | None
|
Allowed values for an |
None
|
serializable
|
bool | None
|
Override for whether the value can be serialized; when
|
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/pyramids/processing/schema.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | |
is_serializable
property
#
Whether a value for this parameter can be written to a pipeline file.
coerce(raw)
#
Coerce a raw CLI string into this parameter's type.
Public API kept for a future CLI --set key=value path; not yet wired
into a shipped command (the run subcommand reads typed parameters from YAML).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw
|
str
|
The string value from the command line. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
The value converted to the parameter's Python type. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/pyramids/processing/schema.py
help()
#
Render a one-line CLI/help description of this parameter.
Source code in src/pyramids/processing/schema.py
validate(value)
#
Validate value against this parameter's type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The value supplied for the parameter. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/pyramids/processing/schema.py
pyramids.processing.resolve(name)
#
Return the :class:ToolMetadata registered under name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The tool name referenced by a pipeline or the CLI. |
required |
Returns:
| Type | Description |
|---|---|
ToolMetadata
|
The registered :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no tool is registered under |
Source code in src/pyramids/processing/registry.py
pyramids.processing.catalog()
#
Return a read-only {name: ToolMetadata} view of the registered tools.
Named catalog (not registry) so it does not shadow the
pyramids.processing.registry submodule when re-exported at the package root.