Minimal demand-driven query framework for incremental computation.
Project description
Cascade Query
Releases: https://pypi.org/project/query-cascade/
cascade-query is a minimal, demand-driven incremental computation framework for Python.
It is designed for compiler-like workloads where you want:
- lazy pull-based evaluation
- precise dependency tracking
- red-green early bailout (backdating)
- query dedup across concurrent callers
- snapshot isolation for concurrent reads
- safe cancellation of obsolete background work
- side-effect replay on cache hits
- persistence + graph inspection
Minimal API
from cascade import Engine
engine = Engine()
warnings = engine.accumulator("warnings")
@engine.input
def source(file_id: str) -> str:
return ""
@engine.query
def parse(file_id: str) -> tuple[str, ...]:
return tuple(line.strip() for line in source(file_id).splitlines() if line.strip())
@engine.query
def symbols(file_id: str) -> tuple[str, ...]:
return tuple(row.split("=")[0].strip() for row in parse(file_id))
Primitives
engine.input(fn)
Wraps mutable roots. Use.set(...)to create new revisions.engine.query(fn)
Wraps pure demand-driven queries with memoization and dependency capture.engine.accumulator(name)
Creates thread-safe side-effect channels replayed on cache hits.engine.snapshot()
Captures an immutable read view (Snapshot) for MVCC-like isolation.engine.submit(query, *args, snapshot=...)
Runs a query in the background with cancellation if inputs mutate.engine.compute_many([(query, args), ...], workers=N)
Multi-threaded execution with a work-stealing scheduler.engine.inspect_graph()/engine.traces()
Introspection hooks for diagnostics.engine.save(path)/engine.load(path)
Persist or recover graph/cached state from SQLite.engine.prune(roots)
Garbage-collect memoized subgraphs not reachable from roots.
Design Notes
What this framework guarantees
- Smart recalculation: only stale demand paths recompute.
- Selective updates: unchanged parents remain green after child backdating.
- Query deduplication: one in-flight compute serves all identical concurrent requests.
- Cycle detection: recursive query cycles raise
CycleError. - Cancellation: stale background queries raise
QueryCancelled.
Limitations and enforceability boundaries
- CPython GIL and CPU-bound work:
compute_manyand dedup execution are multi-threaded, but true CPU parallel speedup is only guaranteed when query bodies release the GIL (e.g. I/O waits, native extensions). For pure Python CPU-bound loops, overlap exists but throughput may remain effectively single-core. - Process-level durability model: persistence is an explicit point-in-time snapshot (
save/load), not a transactional WAL-backed MVCC store shared by multiple live processes. - Boundary of side-effect replay guarantees: replay is guaranteed only for effects emitted through
Accumulator; out-of-band side effects in query bodies (printing, network calls, filesystem writes) are intentionally not replayed. - Cycle handling scope: direct and long-chain dynamic query cycles are detected and raised as
CycleError; this engine does not implement fixed-point solvers for cyclic dataflow.
What this framework intentionally does not include
To keep API surface minimal, this version does not include:
- nominal interning APIs (
@interned) and tracked structs (@tracked) - fixed-point cycle solvers
- distributed/shared cache protocols
Those can be layered on top without changing the core query model.
Quickstart
from cascade import Engine
engine = Engine()
@engine.input
def text() -> str:
return ""
@engine.query
def lint_count() -> int:
value = text()
return value.count("TODO")
text.set("TODO: one\nTODO: two")
assert lint_count() == 2
# No recompute needed if input did not semantically change.
text.set("TODO: one\nTODO: two")
assert lint_count() == 2
Examples
examples/compiler_pipeline.py
Tiny compiler pipeline (source -> parse -> symbol_names -> typecheck) with warnings accumulator.examples/dynamic_macro_expansion.py
Runtime macro-expansion query that dynamically changes downstream graph dependencies.
Persistence and inspection
engine.save("state.db")
engine.load("state.db")
print(engine.inspect_graph())
for event in engine.traces():
print(event.event, event.key, event.detail)
Analysis review of the uploaded notes
Your friend’s notes are largely directionally correct and align with state-of-the-art incremental systems:
- Correct: pull-based demand, red-green early bailout, dependency graph capture, dedup, MVCC snapshots, cancellation, side-effect replay, tracing, and persistence.
- Needs qualification in Python: true CPU-bound parallelism is constrained by the GIL unless query bodies release it (I/O/native extensions).
- Overreach for this minimal implementation: unsafe-pointer lifetime tricks, red/green syntax tree internals, and fixed-point cycle solving are advanced optimizations that are not required for a practical minimal API.
Running tests
python -m pip install -e . pytest
pytest -q
CI best practices included
- GitHub Actions workflow at
.github/workflows/ci.yml. - Runs on both pushes and pull requests.
- Linting with
ruffbefore tests. - Separate package-build job (
python -m build) to catch packaging regressions early.
Project details
Release history Release notifications | RSS feed
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 query_cascade-0.1.2.tar.gz.
File metadata
- Download URL: query_cascade-0.1.2.tar.gz
- Upload date:
- Size: 15.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba4e81abd312416f8d73e127f728a115c4984bfae9cc35e46489480f78378aa1
|
|
| MD5 |
2ea9c1650ab33eb74499e86dea87c07f
|
|
| BLAKE2b-256 |
c5050332a6f3e74eb5b041cc9699618b4b38a39b92ae04cfccd251f7449b13d0
|
Provenance
The following attestation bundles were made for query_cascade-0.1.2.tar.gz:
Publisher:
workflow.yml on hmatt1/cascade-query
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
query_cascade-0.1.2.tar.gz -
Subject digest:
ba4e81abd312416f8d73e127f728a115c4984bfae9cc35e46489480f78378aa1 - Sigstore transparency entry: 1250734630
- Sigstore integration time:
-
Permalink:
hmatt1/cascade-query@94b10df9ab7c44343ef5ca310071056f304b2f78 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/hmatt1
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@94b10df9ab7c44343ef5ca310071056f304b2f78 -
Trigger Event:
push
-
Statement type:
File details
Details for the file query_cascade-0.1.2-py3-none-any.whl.
File metadata
- Download URL: query_cascade-0.1.2-py3-none-any.whl
- Upload date:
- Size: 9.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c9433a236a5113ce12aa809c2716368e02b55c050c2f961b86f64910872e190
|
|
| MD5 |
973a54fa2f93b2959d8b55b07cf349c3
|
|
| BLAKE2b-256 |
cc49aed8ae7b69ee2a0812ca46babd5afb2d76194709ccc35e4ceb1dcae706ee
|
Provenance
The following attestation bundles were made for query_cascade-0.1.2-py3-none-any.whl:
Publisher:
workflow.yml on hmatt1/cascade-query
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
query_cascade-0.1.2-py3-none-any.whl -
Subject digest:
0c9433a236a5113ce12aa809c2716368e02b55c050c2f961b86f64910872e190 - Sigstore transparency entry: 1250734639
- Sigstore integration time:
-
Permalink:
hmatt1/cascade-query@94b10df9ab7c44343ef5ca310071056f304b2f78 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/hmatt1
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@94b10df9ab7c44343ef5ca310071056f304b2f78 -
Trigger Event:
push
-
Statement type: