Python nodes can read SQL models and sources at runtime, but they cannot depend on them as graph edges (see the SQL boundary). Typed references make this read-only access explicit and safe across direct and virtual modes.
Declaring a reference
Use model() and source() from sqlbuild.refs in a node’s depends_on:
from sqlbuild.refs import model, source
from sqlbuild.tasks import task
@task(depends_on=model("fact_orders"))
def export_orders(ctx):
...
@task(depends_on=source("raw_orders"))
def inspect_raw(ctx):
...
Declaring the reference does two things:
- It tells SQLBuild the node reads that SQL resource, so the node is scheduled after the resource is built (read-side).
- It authorizes
ctx.relation(...) to resolve that reference at runtime.
It does not make the SQL resource depend on the Python node. The dependency is one-way: Python reads SQL, never the reverse.
Resolving with ctx.relation
Always resolve a reference to its concrete relation with ctx.relation(...) instead of hardcoding the table name:
@task(depends_on=model("fact_orders"))
def export_orders(ctx):
relation = ctx.relation(model("fact_orders"))
rows = ctx.query(f"SELECT * FROM {relation}").fetchall()
return ctx.result(metadata={"rows": len(rows)})
ctx.relation(...) returns the adapter-qualified relation name for the current run. Passing a reference that was not declared in depends_on raises an error.
Do not hardcode model or source names in raw SQL. In virtual mode a model resolves to a versioned VDE relation (for example marts__feature_x.fact_orders), not the bare name. A query like ctx.query("SELECT * FROM fact_orders") will fail or read the wrong relation. Always use ctx.relation(model("fact_orders")).
model vs source
| Reference | Resolves to |
|---|
model("name") | The built model relation (the VDE logical relation in virtual mode) |
source("name") | The source read relation, following deferred-source semantics |
source(...) respects defer_sources_to, so a node reading a source in dev can read the deferred target’s data just like SQL models do.
Where references are allowed
- Tasks and assets may declare
model() and source() references and read them with ctx.relation(...).
- Checks may not reference SQL resources. Validate SQL with audits.
- A Python node referencing a SQL resource never turns into a SQL dependency; selector expansion will not pull Python outputs into SQL model dependencies.