Skip to main content

keystones-dbt

Gate a dbt model on the SQL it means, not on the text it is written as.

A keystones keystone pins a review gate to an AST node. dbt models are Jinja, which no SQL grammar can parse, so without a preprocessor they can only be gated on normalised text - which trips on every reformat.

This package is two plugins. The preprocessor masks the templating so the SQL underneath parses, and hands the masked content back so it is still gated. The parser reads any SQL dialect sqlglot knows, for warehouses the tree-sitter grammar pack has no grammar for.

Install

pip install "keystones-dbt[sqlglot]"
[[tool.keystones.language]]
extensions   = [".sql"]
parser       = { plugin = "keystones_dbt.parsers:sqlglot", dialect = "snowflake" }
preprocessor = { plugin = "keystones_dbt:preprocess", control_flow = "first-branch" }

dialect is any sqlglot knows: snowflake, bigquery, redshift, databricks, postgres, duckdb and more. Parsing is offline; nothing connects to a warehouse. Where the grammar pack has a grammar for your dialect you may use builtin = "sql_bigquery" in place of parser and skip the extra.

What the mask does

Jinja becomes
{# comment #} removed
{{ config(...) }} alone on a line removed
any other {{ ... }} a placeholder derived from its content
{% set x = 1 %}, {% do %}, {% import %}, {% from %} removed
{% if %}, {% for %} governed by control_flow, below
{% macro %}, block {% set %}, {% call %}, {% raw %}, other block tags refused

Masked content is hashed verbatim, so changing ref('orders') to ref('payments') trips the gate while reformatting the expression does not.

A keystone hashes its own lines, so a node keystone on a CTE does not see the config() block above it or an incremental filter below it. To gate materialization or the filter, use keystone(file).

Control flow

control_flow {% if a %} x {% else %} y {% endif %}
first-branch (default) tags removed, x kept and masked, y removed; the whole block is hashed as one span
drop the whole block removed and hashed as one span
refuse the file is refused; gate it on text with a region

With first-branch the SQL of the first branch still parses and anchors nodes. The whole block, every branch included, is in the hash, so a change to y still gates and {% if a %}x{% endif %}y cannot collide with x{% if a %}y{% endif %}. A block whose first branch is not valid SQL on its own fails to parse and is reported with the hash=text guidance.

A block that opens or closes outside a keystone's target, because a region or CTE boundary cuts through it, is refused: gate the whole file or a region that contains the whole block.

Refused models can always be gated on text with a region:

-- keystone:start(finance, hash=text): revenue-recognition
    amount * 0.97 as net_revenue
-- keystone:end

Macros

A {% macro %} in a model is refused. Files under macros/ are SQL fragments that no dialect parses as statements; gate them with keystone(file) or a region on hash=text.

Metadata

Release files for keystones-dbt 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for keystones-dbt 0.1.0
File Size Uploaded
keystones_dbt-0.1.0.tar.gz 16.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for keystones-dbt 0.1.0
File Interpreter ABI Platform
keystones_dbt-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 26.3 kB

Release files / keystones_dbt-0.1.0.tar.gz

Download URL keystones_dbt-0.1.0.tar.gz
Size 16.8 kB
Tags Source
SHA-256 checksum
How to use checksums
8742f17b5b071359b388e232e215180848cc831ce749bd7a2e43e92ded05cd89
BLAKE2b-256 checksum
How to use checksums
e986a14a93360037a77dee33a6d007a9c6ab459397e8aa33cf0e33324b305b03
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / keystones_dbt-0.1.0-py3-none-any.whl

Download URL keystones_dbt-0.1.0-py3-none-any.whl
Size 9.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dbf3c6dfcffff2163636d4469efb23d6cae34898b37ade8e7ff79b66c846b21a
BLAKE2b-256 checksum
How to use checksums
5628e185bc7c1e5a25d1dce1d7258366965a63558e72a4b190c1f129486130b8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.2.0

2 release files

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page