What pipekit ships
Report 2 · pipekit's surface, now documented in pipekit; the planning stays here
Abstract¶
This report began as the proposal for pipekit’s first public surface and became a record of what pipekit 0.0.2 ships. The record now lives with the code, as pipekit’s tour of the core: every module, group by group, with examples checked against a real run and a list of today’s limits. This page keeps what is GeoStack planning rather than pipekit documentation: where the deferred operators went, the open questions and the upcoming work.
About this report
| Status | The surface moved to pipekit’s docs; the planning stays here |
| Audience | anyone deciding what belongs in pipekit core, or what to build next |
| Companions | Report 1 (background, now in pipekit’s docs); Report 3 (sister libraries); Report 9 (use cases, distilled into pipekit’s patterns); Report 10 (cycle); Report 11 (train); Report 12 (experiment); Report 13 (state catalog) |
| Checked against | pipekit 0.0.2 (ef3c17f, the revision pinned in references/geostack/pipekit), and pipekit main when the tour moved |
Where each group went¶
The proposal organised pipekit by semantic group, one module each, and that organisation shipped (Figure 1). Each group below links its section in the tour and keeps the one difference from the plan that matters to a user; the full inventory has the symbols and line counts.
Figure 1:pipekit 0.0.2 by group, coloured by how each matches the plan.
Group A · Foundations¶
Now Foundations in the tour. Operator, ConfigMixin, Sequential, Graph, Input, Node. Differs from the plan: no Graph.summary() and no signatures through Graph.
Group B · Composition¶
Now Composition in the tour. pipe, compose, compose_left, juxt, complement, as planned.
Group C · Building blocks¶
Now Building blocks in the tour. Identity, Const, Lambda, Sink, as planned.
Group D · Control flow¶
Now Control flow in the tour. Branch, Switch, Try, Coalesce, Retry. Differs: Try and Retry are not flagged forbid_in_yaml.
Group E · Observers¶
Now Observers in the tour. Tap, Snapshot, ShapeTrace, Profile, Histogram. Differs: no ShapeTrace hook for an extra line.
Group F · Combination¶
Now Combination in the tour. Fanout, as planned.
Group G · Caching¶
Now Caching in the tour. Cache, Memoize, as planned.
Group H · Quality control¶
Now Quality control in the tour. Quarantine, four Assert* operators and QCError, as planned plus QCError.
Group I · Shape inference¶
Now Shape inference in the tour. Signature, compute_output_signature. Differs: an unknown dimension prints ? instead of raising, and inference stops at Sequential.
Group J · Parallelism¶
Now Parallelism in the tour. ThreadMap, ProcessMap, AsyncMap, BatchedMap, check_pickleable. Differs: BatchedMap batches lists, not array axis 0.
The pickleability discipline¶
Every operator in a process-pool pipeline must pickle, and closures do not. The discipline (forbid_in_yaml, check_pickleable) is in the tour’s Parallelism section.
Group K · Where the deferred operators went¶
The proposal used Group K for operators that are carrier-specific and so do not belong in core. pipekit 0.0.2 reuses the letter: its docstring reserves Group K for a disk-cache backend, and nothing ships under it. The deferred list is still worth tracking, because most of it has not landed anywhere. Table 1 checks each one against the capability index of every upstream library.
Table 1:The proposal’s deferred operators, and where each one is at pipekit 0.0.2, geotoolz 0.10.2 and xrtoolz 0.0.5.
| Operator | Why not core | Planned home | Status |
|---|---|---|---|
ModelOp | NumPy-specific (np.asarray, np.concatenate) | pipekit-array, or geotoolz / xr_toolz | in geotoolz; pipekit-jax adds JaxModelOp |
ApplyToBands | NumPy (np.take, np.stack) | pipekit-array | not shipped |
Subsample | NumPy slicing | pipekit-array | not shipped |
Diff | NumPy reductions | pipekit-array | not shipped |
AssertValueRange, AssertNoNaN, AssertValidFraction | reductions on the array | pipekit-array, or geotoolz / xr_toolz | not shipped |
Mode, ModeGated, pipeline_mode | global mode state (contextvars) | deferred: open design questions | not shipped, as planned |
Provenance, Watermark | carrier-specific metadata | geotoolz / xr_toolz | not shipped |
Augment | xr.merge | xr_toolz | in xrtoolz, as planned |
ApplyToEach | xr.merge | xr_toolz | in xrtoolz, as planned |
Spy, Hook | cross-cutting hooks: open design questions | deferred; the hook stub is reserved | not shipped, as planned |
pipekit-array exists (0.0.2), but it ships four names (array_namespace,
ConcatenateAlong, StackAlong, MeanScalar), none of them from this list.
It is the planned home for most of the list, which makes it the biggest gap
between plan and code. Report 3 covers it.
Group L · Serialisation¶
Now Serialisation in the tour. dumps, loads, loads_sandboxed, register, unregister, allowed. Differs: no YAML or Hydra extras in core; nested pipelines do not round-trip.
Group M · State¶
Now State in the tour. StatefulOperator, CarryState. Differs: Graph does not thread state.
Group N · Protocols, new¶
Now Protocols in the tour. Predictor, FittableTransformer: structural seams the plan did not have.
Shared hashing (hashing.py), new¶
stable_json, stable_repr and sha256_hex, shared by pipekit-experiment’s registry; pipekit’s patterns page uses them for orchestrator task keys.
The full inventory¶
Table 2 is the canonical list of what each group ships, with the proposed and shipped line counts side by side.
Table 2:The v0.1 inventory as proposed, against pipekit 0.0.2. The proposal’s line counts are estimates; the shipped counts include docstrings.
| Group | Module | Shipped symbols | Proposed lines | Shipped lines | Matches the plan |
|---|---|---|---|---|---|
| A · Foundations | _base/ | Operator, ConfigMixin, Carrier, Sequential, Input, Node, Graph | ~600 | 837 | differs: no Graph.summary or signatures |
| B · Composition | compose.py | pipe, compose, compose_left, complement, juxt | ~60 | 104 | yes |
| C · Building blocks | blocks.py | Identity, Const, Lambda, Sink | ~120 | 145 | yes |
| D · Control flow | control.py | Branch, Switch, Try, Coalesce, Retry | ~200 | 373 | differs: Try, Retry unflagged |
| E · Observers | observe.py | Tap, Snapshot, ShapeTrace, Profile, Histogram | ~250 | 348 | differs: no ShapeTrace hook |
| F · Combination | combine.py | Fanout | ~80 | 64 | yes |
| G · Caching | cache.py | Cache, Memoize | ~80 | 120 | yes |
| H · Quality control | qc.py | Quarantine, four Assert*, QCError | ~130 | 228 | yes, plus QCError |
| I · Shape inference | signature.py | Signature, compute_output_signature | ~150 | 105 | differs: ? not raise |
| J · Parallelism | parallel.py | ThreadMap, ProcessMap, AsyncMap, BatchedMap, check_pickleable | ~250 | 286 | differs: list batching |
| K | — | nothing (reserved for a disk cache) | — | — | repurposed |
| L · Serialisation | serial.py | dumps, loads, loads_sandboxed, register, unregister, allowed | ~80 | 144 | differs: no extras |
| M · State | state.py | StatefulOperator, CarryState | ~150 | 123 | differs: no Graph support |
| N · Protocols | protocols.py | Predictor, FittableTransformer | — | 61 | new |
| Hashing | hashing.py | internal | — | 84 | new |
| Total | 52 public names | ~2,150 | 3,164 |
What is intentionally not here¶
The proposal’s exclusions all held at 0.0.2:
Distributed execution (Dask, Ray, Beam, Flink): the orchestrator’s job.
Automatic differentiation and JAX
jitas pipekit features: they live in a separate package, pipekit-jax. They do not clash with dual-mode__call__, as this page first said: a tracer is not aNode, so a pipeline of JAX operators already runs underjit,vmapandgradwith respect to its inputs (Report 5).Type-checking operator chains at construction:
Sequential([op_a, op_b])does not check thatop_a’s output type matchesop_b’s input.Signaturechecks shape; type checking is a stretch goal.Carrier-specific operators: see Section ?? and Report 3.
A GUI or pipeline builder: a possibility, not in scope.
Workflow scheduling (Airflow, Prefect, Dagster): adapters belong in extras or downstream libraries. pipekit-experiment’s DVC, Hydra and Metaflow adapters are the first of these.
Open questions¶
The proposal carried seven scoping questions, each with a lean (Table 3). The shipped code settles six of them and partly settles question 4; its leans on questions 3 and 5 were overturned.
Table 3:The proposal’s scoping questions, and how pipekit 0.0.2 answered them.
| # | Question | The proposal’s lean | At 0.0.2 |
|---|---|---|---|
| 1 | Name: pipekit, or opkit, composable, pipekit-core? | pipekit | settled: pipekit (the PyPI distribution name is revisited in Report 16 §F) |
| 2 | Is ConfigMixin always on? | yes, with __config_mixin_auto__ and __config_exclude__ | settled as leaned |
| 3 | How does Signature meet carriers without named dims? | None opts out; summary raises a clean error | settled differently: None opts out, summary prints ? |
| 4 | How is YAML round-trip enforced? | the YAML loader rejects flagged operators; an optional strict=True dumper | partly settled: pipekit-experiment’s HydraConfigLoader.from_yaml loads YAML, nested pipelines included; nothing dumps a nested pipeline, and from_state already rejects flagged operators |
| 5 | Hydra-zen built in, or an extra? | an extra, pipekit[hydra] | settled differently: an extra on pipekit-experiment, pipekit-experiment[hydra] (hydra-core and hydra-zen), not on pipekit |
| 6 | Which of Coalesce, Retry, Mode, Provenance to promote? | ship Coalesce and Retry; defer Mode and Provenance | settled as leaned |
| 7 | AsyncMap only, or AsyncSequential too? | AsyncMap only | settled as leaned |
The differences recorded above raise six new questions that need a decision rather than a fix:
Should
Graphthread state? TodaySequentialdoes andGraphdoes not. EitherGraphlearns to, or the docs say stateful operators areSequential-only. DA cycles with several inputs would want the former.Should
CarryStatebe frozen? If yes, it becomes a frozen dataclass and the hash is safe. If not, it should stop defining__hash__, since states routinely hold arrays.What dumps a nested pipeline? Flat operators round-trip through
dumps/loads;Sequential,Try,Cacheand the rest do not. Loading is answered by pipekit-experiment’sHydraConfigLoader, which builds nested pipelines from hand-written YAML; the open half is the other direction, a dumper that writes a built pipeline as nested{"class", "config"}payloads or_target_YAML.Should
AsyncMap.__call__work inside a running loop? At the moment a server handler must know to call.run. An alternative is to detect a running loop and fail with a message that names.run.Should shape inference be wired through
GraphandFanout? OnlySequentialthreads signatures today, so aGraphreports its input signature as its output.Should a
Graph’sstatedescribe the whole graph? Today it records the inputs and the operators that produce the outputs, not the steps upstream of them, so two graphs that differ in an upstream step have equalstateand hash the same. Anything that keys work by a pipeline’s hash (the registry, orchestrator tasks, use cases 9, 12 and 15) needs the whole graph, which is also what aGraphdumper (question 3) would write.
Upcoming work¶
Changes whose shape is already clear (Table 4). Each is a candidate issue on pipekit or a sister library.
Table 4:Follow-ups from checking the proposal against pipekit 0.0.2.
| Follow-up | Where | Why |
|---|---|---|
Fix the compute_output_signature docstring: summary shows ?, it does not raise | pipekit _base/operator.py | the docstring contradicts the behaviour |
Fix the dumps docstring: a flagged operator fails with RuntimeError, not TypeError | pipekit serial.py | the same |
Add Graph.summary() and signature propagation through Graph | pipekit _base/graph.py | proposed and not shipped |
Make Graph.state record every node, not only the output operators | pipekit _base/graph.py | two graphs differing upstream hash the same (question 6) |
Override compute_output_signature in Fanout and the parallel maps, returning None | pipekit combine.py, parallel.py | today they report a passthrough signature for a dict or a list |
Route ProcessMap(on_error="log_and_continue") through logging | pipekit parallel.py | deployments cannot capture or silence stderr prints |
Add a ShapeTrace hook for an extra line (the geotoolz CRS line) | pipekit observe.py | proposed and not shipped |
Ship axis-0 batching, ApplyToBands, Subsample, Diff and the numeric asserts | pipekit-array | assigned there by the proposal; nothing has shipped |
Decide where Provenance and Watermark live, and build them | geotoolz, xrtoolz | assigned there by the proposal; not shipped |
Build CatalogPipeline on ProcessMap / ThreadMap | a sister library (geotoolz-catalog) | use cases 2 and 12 assume it |
References¶
Citations¶
To be added: toolz, the Python Array API standard, and the use-case
gallery, as entries in references.bib.