This release is a pre-release and may not be stable for production use.
RecordStream
RecordStream is a high-performance, functional data processing engine built for modern Machine Learning pipelines. It provides a clean, fluent API for streaming and transforming data from any source while maintaining strict compatibility with PyTorch and Hugging Face.
Part of the Modular Quartet: Loggair, Confluid, Liquifai, and RecordStream.
🚀 Key Features
- A record is a plain dict: the record model — a
dictof typed values (Image,Mask,Boxes,Label,MultiLabel, …), each owning its own metadata, with key names carrying meaning ("image","mask","bboxes"). No wrapper container, no role tags. - Libraries run AS-IS: bare albumentations and torchvision
transforms.v2transforms drop straight into any ops list — the engine invokes each op family natively (one call = one joint draw across image/mask/boxes). No adapter classes anywhere. - Type-dispatched native ops: a
Transformsamples its parameters once per record and applies a per-type kernel to every value it handles — teach an existing op a new value type with one@MyOp.kernel(NewType)registration. - Graph pipelines: readable
flow:documents of named steps —from:forks,merge_from:merges,bind:feeds one step's value into another's parameter. Anops:list is the same engine's linear spelling; both parse to one step graph. - High Performance: Native multiprocess support via
.parallel(workers=N)using the safespawncontext; 1→N expanding ops flatten in every route. - Advanced Storage: HDF5, Zarr and Directory backends with matching read-back sources and metadata-only querying — filter stored datasets without loading a single array.
- Passive Introspection: ops declare the value types they handle / consume / produce and are discoverable by category for visual editors and schema generators.
- 100% Reproducibility: Entire pipelines are serializable via Confluid manifests.
🛠 Quick Start
One pipeline mixing a bare albumentations Compose (image + mask + boxes move together in one draw), a bare torchvision v2 transform, and a native op — no wrappers (mirrors examples/record_pipeline.py):
import albumentations as A
import numpy as np
from recordstream import Stream, Image, Label, Mask, as_transform
records = [
{
"image": Image(rng.random((16, 20, 3)).astype(np.float32)), # typed: knows its layout
"mask": Mask((rng.random((16, 20)) > 0.5).astype(np.uint8)),
"bboxes": [[2, 3, 6, 7]], # albumentations vocabulary
"labels": ["drone"],
"class": Label("drone_x", classes=["noise", "drone_x"]), # typed: knows its vocab
"gain_db": -3.0, # a scalar is just another key
}
for rng in (np.random.default_rng(i) for i in range(100))
]
stream = Stream(
source=records,
ops=[
A.Compose( # bare albumentations — as-is
[A.HorizontalFlip(p=0.5)],
bbox_params=A.BboxParams(format="pascal_voc", label_fields=["labels"]),
),
A.GaussNoise(p=1.0), # image only (its own kwarg vocabulary)
as_transform(lambda d: d - 0.5, handles=(Image,)), # native: a plain function op
],
).parallel(workers=4)
for record in stream:
print(record["image"].shape, record["class"].value) # image+mask+boxes flipped together
The same ops list in Confluid YAML — bare library transforms are ordinary !class: nodes:
ops:
- !class:albumentations.HorizontalFlip
p: 0.5
- !class:albumentations.GaussNoise
p: 1.0
- !class:recordstream.ops.numpy.Threshold
low_level: 0.5
Toggling a branch from the CLI (Enable)
Wrap any stretch of an ops list in Enable to switch the whole chain on or off from one flag.
The toggle is the declared enabled parameter; name identifies the wrapper so several of them
toggle independently:
ops:
- !class:recordstream.ops.numpy.Threshold {low_level: 0.5}
- !class:recordstream.ops.enable.Enable
name: visualize # ← names THIS wrapper; scopes its CLI flag
enabled: false # ← off by default; the chain below is skipped
ops:
- !class:recordstream.ops.image.ConvertToImage {}
- !class:recordstream.ops.debug.PrintRecordOp {}
recordstream run pipeline.yaml --visualize.enabled true # this wrapper only
recordstream run pipeline.yaml --visualize.enabled+ # polarity shorthand → True
recordstream run pipeline.yaml --enabled false # broadcast: every Enable off
Inner ops are not materialized until the wrapper first fires, so gating an expensive chain with
enabled: false costs nothing at startup. In Python the same wrapper is one call —
Enable(ops=[...], name="visualize", enabled=False) — which is what lets a visual editor or a
generated tool schema set the toggle too (see docs/architecture.md).
Inference as an op (ModelPredict)
A pipeline can carry its own inference: recordstream.ops.predict.ModelPredict runs any
callable model wrapper on each record and stamps the prediction back as a record field —
a class Label, Boxes, an int class mask, or the restored image, by kind. The model's
heavy work (build the network, load checkpoint_path) happens in its solidify(), called
lazily on the first record; the op itself imports no ML framework.
pipeline: !class:recordstream.core.stream.Stream
source: !class:recordstream.sources.huggingface.HuggingFaceSource {path: ylecun/mnist, split: test}
ops:
- !class:recordstream.ops.image.ConvertToImage {width: 224, height: 224}
- !class:recordstream.ops.predict.ModelPredict
model: !class:<your model wrapper> {checkpoint_path: runs/checkpoints/mnist/last.ckpt}
kind: classification # or detection / segmentation / restoration
A viewer reads the stamped predict* fields back as layers; recordstream run executes
the same document offline.
📚 Documentation
| Page | Covers |
|---|---|
| docs/record-model.md | The record data model: a plain dict of typed values, type-dispatched ops and kernels, mixing libraries as-is, custom item types, engines, storage layout |
| docs/kinds.md | Writing ops (kernels, field=, type-changing ops), the collate registry (collate_records) + its read-back (batch_values / batch_tensor / batch_metadata), the Keras RecordSequence adapter, 1→N expanding ops |
| docs/graph.md | flow: documents + the FlowGraph engine, ops: as the linear spelling of the same step graph, expanding (1→N) steps, Stream.from_ops_yaml |
| docs/sources.md | HuggingFaceSource, DatasetSplit train/val/test views, RangeSource, ConcatSource, Confluid !ref: sharing, dataset identity (dataset_uri / dataset_url) |
| docs/storage.md | HDF5 / Zarr / Directory sinks & sources (typedrecord-v1), array-valued item attributes, the SupportsMetadataScan protocol + MetadataFilterSource querying |
| docs/projection.md | Key projection (SupportsProjection), lazy key walks (iter_key), one-peek first_value, num_classes, the fittable LabelMap, class-balance weights |
| docs/predictions.md | The model boundary: prediction-output contracts (ClassificationOutput & co), ensure_record_dataset, the PredictionsSink protocol + the classification sink |
| docs/image.md | Generic value→image conversion (ConvertToImage, normalize_to_uint8), mask→class-id conversion (ConvertToMask), array introspection helpers |
| docs/configure.md | Per-record op parameters (ConfigureOp and the Capture/Apply context ops) |
| docs/runnable.md | Runnables (run() + recordstream run), the @entrypoint task/role markers + run_entrypoint dispatch with a worked example, TorchRunner / ProgressReporting |
| docs/workflow.md | Workflow combinators (Sequence/Conditional/Switch + predicates): resume-safe multi-stage pipelines as ONE document |
| docs/augmentation.md | Augmentation via bare albumentations / torchvision transforms.v2 — the op-family dispatch, key vocabulary, bbox recipes, seeding |
| docs/architecture.md | Architecture decision records — the why behind non-obvious mechanisms (e.g. why collation is a pluggable registry) |
🧭 Scope: a modality-neutral engine
RecordStream deliberately contains no domain-specific code — every op, source and sink in this package is meaningful for any modality (arrays, tensors, images, generic metadata). Domain packages build on it and keep their own vocabulary:
- Signal/waveform items and ops (spectrograms, FFT windows, recording formats) live in the domain package, which registers its item types into the same registries.
- Task-specific trainers, collates and models live in their consuming projects.
🌐 Ecosystem Integration
RecordStream is designed to sit between your data catalog and your training loop, acting as the high-performance "glue" for ML pipelines:
- Hugging Face for community datasets and Arrow/Parquet loading —
HuggingFaceSourceturns adatasets.Datasetinto record dicts of typed values with full metadata traceability, and names the dataset it reads so a run record can point at it (see docs/sources.md). - Confluid for configuration: every pipeline is a YAML document, every op a
!class:node — including bare library transforms — every run reproducible. - PyTorch:
StreamandFlowGraphimplement theDatasetprotocol (__len__/__getitem__/.batch/.parallel) and plug straight into aDataLoaderwith a registry collate (collate_recordsis the default). - Keras 3: no
DataLoaderexists to do the batching, soRecordSequenceis thekeras.utils.PyDatasethalf — row order, slicing, per-epoch reshuffle,collate_records— and atransformcallable supplies the batch shape, exactly ascollate_fndoes for torch. - Augmentation libraries: albumentations and torchvision
transforms.v2transforms run as-is in any ops list — the engine speaks each library's native convention (kwarg vocabulary vs dict walk), so there is nothing to wrap (see docs/augmentation.md).
🔧 Installation
RecordStream is on PyPI as a pre-release, so pip needs --pre to see it:
pip install --pre recordstream
The core engine is numpy, and installs no ML framework. A framework arrives only with the extra that needs it:
| Extra | Provides |
|---|---|
torch |
The pieces that genuinely produce tensors — the ToTensor op, batch_tensor, and the classification_output / segmentation_output builders |
keras |
recordstream.keras — the RecordSequence PyDataset adapter and the KERAS_BACKEND ordering. Keras 3 is an API, so this names no compute engine; it runs on whichever of torch / TensorFlow / JAX you have |
pip install --pre "recordstream[torch]"
Everything else works without either. A Stream is map-style (__len__/__getitem__), so a
DataLoader still accepts one directly on a torch install; batch_values, multi_hot and the
class-balance statistics return numpy, so a non-torch backend converts in one line. Reaching for
recordstream.ops.ToTensor without the extra raises an ImportError naming it.
📄 License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file recordstream-0.1.0a1.tar.gz.
File metadata
- Download URL: recordstream-0.1.0a1.tar.gz
- Upload date:
- Size: 257.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a9c61d3ca594fa448ed13eb750ddc4f2099e2a92069575d99c5be1197dd679f9
|
|
| MD5 |
5b565a953e6e16116c26a1a021761d8a
|
|
| BLAKE2b-256 |
3f39ec36a42ad628988ce749ac6233ceed94a7dd72af39f9635974630a2ce3e1
|
Provenance
The following attestation bundles were made for recordstream-0.1.0a1.tar.gz:
Publisher:
release.yml on Gearlux/recordstream
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
recordstream-0.1.0a1.tar.gz -
Subject digest:
a9c61d3ca594fa448ed13eb750ddc4f2099e2a92069575d99c5be1197dd679f9 - Sigstore transparency entry: 2582987213
- Sigstore integration time:
-
Permalink:
Gearlux/recordstream@342d242bfd39b7d25bca20a781c495315803acd9 -
Branch / Tag:
refs/tags/v0.1.0a1 - Owner: https://github.com/Gearlux
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@342d242bfd39b7d25bca20a781c495315803acd9 -
Trigger Event:
push
-
Statement type:
File details
Details for the file recordstream-0.1.0a1-py3-none-any.whl.
File metadata
- Download URL: recordstream-0.1.0a1-py3-none-any.whl
- Upload date:
- Size: 192.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c22c70f3e6f7ae28fc028dd827cbce7cfa8bd81cb51a8ffadd783745749a490
|
|
| MD5 |
8f713002dcfb98099f89e2276a5af846
|
|
| BLAKE2b-256 |
ac291f7c9db84b5e1224c265b4c5cc8147c8ba256c9e2d325a6e6a5399800bdc
|
Provenance
The following attestation bundles were made for recordstream-0.1.0a1-py3-none-any.whl:
Publisher:
release.yml on Gearlux/recordstream
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
recordstream-0.1.0a1-py3-none-any.whl -
Subject digest:
6c22c70f3e6f7ae28fc028dd827cbce7cfa8bd81cb51a8ffadd783745749a490 - Sigstore transparency entry: 2582987224
- Sigstore integration time:
-
Permalink:
Gearlux/recordstream@342d242bfd39b7d25bca20a781c495315803acd9 -
Branch / Tag:
refs/tags/v0.1.0a1 - Owner: https://github.com/Gearlux
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@342d242bfd39b7d25bca20a781c495315803acd9 -
Trigger Event:
push
-
Statement type: