DreamLake

Python SDK

Decorate a function, call it, and get the result back — Lakeshore handles the rest.

Install

The distribution is dreamlake-lakeshore (hyphen); the import path is dreamlake.lakeshore (dot). import lakeshore is not a thing — dreamlake is an implicit namespace package, so there is no top-level lakeshore module.

bash
pip install dreamlake-lakeshore
uv add dreamlake-lakeshore        # or with uv
python
import dreamlake.lakeshore as dls

Python 3.11 or newer. The runtime dependencies are small and pure-Python: cloudpickle, httpx, msgpack, params-proto, python-ulid, pyyaml, typing-extensions.

Verify the install, and read the version from importlib.metadata — dreamlake.lakeshore.__version__ is a hardcoded "0.0.0" placeholder that does not track releases:

bash
python -c "import dreamlake.lakeshore as dls; print(dls.SyncQueue)"
python -c "from importlib.metadata import version; print(version('dreamlake-lakeshore'))"

Extras

ExtraPulls in
testpytest, pytest-xdist
devtest plus build, ruff
servernothing today — a reserved, deliberately empty extra
alltest + server + dev
bash
pip install "dreamlake-lakeshore[dev]"
The SDK installs no console scripts

pyproject.toml declares no [project.scripts]. There is no lakeshore-daemon command — it was retired in 0.3.6. Run a worker with python -m dreamlake.lakeshore.daemon, or through the TypeScript CLI (lakeshore worker start, npm @dreamlake/lakeshore). See Dispatch planes.

One pattern, end to end

python
import dreamlake.lakeshore as dls

@dls.udf(queue="compute")
def square(x: int) -> int:
    return x * x

q = dls.SyncQueue("compute")
ids = [square.submit(i) for i in range(8)]        # durable string ids
results = [q.result(i, timeout=60.0) for i in ids]

The list comprehension is the spawn; the result loop is the barrier. There is no Future type — a pending job is its invocation id, a plain string you can persist and reconnect with from any process.

No gather, no futures

The SDK has no gather, no as_completed, and no Future class. Fan-out is a comprehension of submit calls plus a loop of q.result; on the async Queue, stdlib asyncio.gather composes over q.result coroutines.

Data UDFs in one breath

A data UDF reads and writes files through dls.run and returns plain string keys. File bytes never ride the msgpack wire — only keys do.

python
@dls.udf
def splats_to_mesh(splats: str) -> str:
    mesh = extract(dls.run.read(splats))          # key -> local Path
    mesh.save(dls.run.write("process/mesh.ply"))  # key -> local Path, recorded
    return "process/mesh.ply"                     # return your keys

with dls.scope("scenes/0007"):                    # prefix for read/write
    key = splats_to_mesh("source/splats.ply")

Surfaces

SurfaceRead for
@udf decoratorOne decorator, four body kinds (sync / async / generator / async-gen), the dls.run I/O seam, the return-your-keys contract, and function transport.
Queue APISyncQueue (blocking) and Queue (async) — submit / result / call / stream, worker verbs, and Topic pub/sub over the frame journal.
Invocation idsThe no-Future model: ids as durable handles, reconnect-by-id, fan-out + collect, and live streaming via q.stream.
Dispatch planesThe minimal local plane (Dispatch) for dev and tests, HttpDispatch against the Node control plane, and the run_worker loop.

What's exported

dreamlake.lakeshore.__all__ is exactly these 22 names:

python
from dreamlake.lakeshore import (
    # Functions
    udf, UDF, thunk, Thunk,
    # The dls.run I/O seam
    scope, run, RunContext,
    # Queues
    Queue, SyncQueue, Topic, Job,
    # Dispatch planes
    Dispatch, HttpDispatch,
    # Worker
    run_worker,
    # Storage
    Storage, TemporaryCredentials,
    # .dreamrc config
    DreamRc, Provider, RunConfig, load_config, resolve,
)

Imports are lazy (PEP 562): import dreamlake.lakeshore loads almost nothing, and purely local code (bare @udf, dls.scope, dls.run) never pulls in httpx or msgpack.

`dls.run` is not a verb

dls.run is the I/O proxy for the ambient run context — dls.run.read / dls.run.write / dls.run.read_all / dls.run.write_all / dls.run.prefix / dls.run.root. It does not run anything. The entry points that execute work are UDF.__call__, .submit, .remote, .local, the queue verbs, and dls.run_worker.

Runnable examples

The SDK repo ships seven zero-infrastructure examples that run on an in-memory Dispatch(":memory:") plane — no control plane, no daemon:

ExampleShows
examples/00_hello_udf.pysubmit → run_worker(once=True) → result
examples/01_fan_out.pyN submits, collect by id
examples/02_pipeline.pytwo stages, the DAG is ordinary Python
examples/03_body_kinds.pysync / async / generator / async-generator
examples/04_ids_not_futures.pyids as durable handles
examples/05_streams_topics.pyq.stream frames and Topic pub/sub
examples/06_dynamic_graph.pywork discovered at run time

Try it end-to-end

Walk the happy paths — five flows from "the decorator works, no network" up to storage access from a worker.