continuo-python-runtime 0.4.1__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,6 +18,11 @@ Dispatches on ``VALIDATION_OP`` env var (default ``build_from_sql``):
18
18
  that dropped a column the script reads fails the release gate, then the output
19
19
  table is materialized empty from the declared typed columns and the declared
20
20
  physical layout.
21
+ - ``check_binds``: for a dbt test's compiled SQL (``CANDIDATE_SQL_URI``, fetched
22
+ the same way as ``build_from_sql``). EXPLAINs it against the candidate schema
23
+ via the engine adapter and creates nothing — a test whose compiled SQL names
24
+ a column a candidate change dropped or renamed fails the release at its
25
+ source, before any table is built.
21
26
 
22
27
  The engine adapter is discovered from the single installed
23
28
  ``continuo_engine.adapters`` entry point — each runner image installs exactly one.
@@ -108,7 +113,7 @@ def load_candidate_spec() -> dict:
108
113
  return spec
109
114
 
110
115
 
111
- _NODE_OPS = ("build_from_sql", "clone_from_prod", "build_from_columns")
116
+ _NODE_OPS = ("build_from_sql", "clone_from_prod", "build_from_columns", "check_binds")
112
117
  _SCHEMA_OPS = ("ensure_schema", "drop_schema")
113
118
 
114
119
 
@@ -116,10 +121,13 @@ def main() -> None:
116
121
  """Run one validation op end to end; exits non-zero on failure.
117
122
 
118
123
  Node ops (``build_from_sql``/``clone_from_prod``/``build_from_columns``)
119
- materialize one empty node table and require ``TABLE_NAME``. Schema ops
120
- (``ensure_schema``/``drop_schema``) act on the whole candidate schema —
121
- the executor schedules them as one-shot engine-image Jobs to own the
122
- candidate-schema lifecycle without connecting to the warehouse itself —
124
+ materialize one empty node table and require ``TABLE_NAME``. ``check_binds``
125
+ is also a node op and requires ``TABLE_NAME`` (for identity only, in the
126
+ result block's ``unique_id``) but creates nothing: it bind-checks a dbt
127
+ test's compiled SQL against the candidate schema with the engine's EXPLAIN.
128
+ Schema ops (``ensure_schema``/``drop_schema``) act on the whole candidate
129
+ schema — the executor schedules them as one-shot engine-image Jobs to own
130
+ the candidate-schema lifecycle without connecting to the warehouse itself —
123
131
  and take no table.
124
132
  """
125
133
  logging.basicConfig(
@@ -139,7 +147,7 @@ def main() -> None:
139
147
  if op in _NODE_OPS:
140
148
  table = _require("TABLE_NAME")
141
149
  unique_id = _node_id() or f"model.{table}"
142
- if op == "build_from_sql":
150
+ if op in ("build_from_sql", "check_binds"):
143
151
  try:
144
152
  raw_sql = load_candidate_sql()
145
153
  except Exception as exc:
@@ -150,7 +158,7 @@ def main() -> None:
150
158
  if not raw_sql:
151
159
  logger.error(
152
160
  "CANDIDATE_SQL_URI is unset or the object is empty for a "
153
- "build_from_sql node; cannot validate"
161
+ "%s node; cannot validate", op
154
162
  )
155
163
  print(result.result_block("error", "CANDIDATE_SQL_URI is unset or empty",
156
164
  unique_id=unique_id), flush=True)
@@ -238,6 +246,12 @@ def main() -> None:
238
246
  if op == "build_from_sql":
239
247
  assert candidate_sql is not None, "candidate_sql must be set for build_from_sql"
240
248
  adapter.build_empty_from_sql(schema, table, candidate_sql)
249
+ elif op == "check_binds":
250
+ # A dbt test: EXPLAIN its compiled SQL against the candidate
251
+ # schema. A dropped or renamed column fails here; no table is
252
+ # created and no row is read.
253
+ assert candidate_sql is not None, "candidate_sql must be set for check_binds"
254
+ adapter.check_binds(candidate_sql)
241
255
  elif op == "build_from_columns":
242
256
  assert spec is not None, "spec must be set for build_from_columns"
243
257
  if csv_source:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: continuo-python-runtime
3
- Version: 0.4.1
3
+ Version: 0.5.0
4
4
  Summary: Runtime harness, contract tooling, and CI lint for Continuo python nodes.
5
5
  Author: Simone Carolini
6
6
  Maintainer: Simone Carolini
@@ -11,7 +11,7 @@ Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Programming Language :: Python :: 3.14
13
13
  Requires-Python: >=3.14
14
- Requires-Dist: boto3==1.43.74
14
+ Requires-Dist: boto3==1.43.85
15
15
  Requires-Dist: continuo-engine-contract==0.7.3
16
16
  Requires-Dist: pyarrow==25.0.1
17
17
  Requires-Dist: pyyaml==6.0.3
@@ -275,9 +275,9 @@ A domain repo picks its warehouse engine by which base image it builds
275
275
  `FROM`:
276
276
 
277
277
  ```dockerfile
278
- FROM ghcr.io/carolsimone/continuo-python-runtime-postgres:v0.4.1
278
+ FROM ghcr.io/carolsimone/continuo-python-runtime-postgres:v0.5.0
279
279
  # or
280
- FROM ghcr.io/carolsimone/continuo-python-runtime-trino:v0.4.1
280
+ FROM ghcr.io/carolsimone/continuo-python-runtime-trino:v0.5.0
281
281
  ```
282
282
 
283
283
  The engine is part of the image **name**; the tag is the bare version, so
@@ -19,11 +19,11 @@ continuo_python_runtime/csv_readers/__init__.py,sha256=9TKvjC37C77uRaJQZuO0--zVj
19
19
  continuo_python_runtime/csv_readers/https.py,sha256=tMJ9k5F0b9SAydpon0ZlOznfjvjhF2BBLltyVmvRneE,4998
20
20
  continuo_python_runtime/csv_readers/s3.py,sha256=zmvHs3TxlN2alPKrdaHzPyREmkve2nBiAsHRXXe1mE0,2246
21
21
  continuo_python_runtime/validation/__init__.py,sha256=hz5oGXsoaUoygR0_pBby9PS6cEfrre518EE0HGB58eE,79
22
- continuo_python_runtime/validation/runner.py,sha256=AwYbiFrQubxSm1vfxJJpnp7xfekviUW2anw4LRQQ4Rc,13062
22
+ continuo_python_runtime/validation/runner.py,sha256=7pbksf7MXfTNcdklCOkOXg9qfRiJtyI_dbgbL3a9LWk,14072
23
23
  continuo_python_runtime/validation/s3.py,sha256=q8nRrT9R7L1-M4dSlDnkL7CUJMPmq86MHY_UKYFlEf8,1785
24
- continuo_python_runtime-0.4.1.dist-info/METADATA,sha256=EjG8OIYrN1O51KOsUxIA0Ln6zpsWdaLJheUcCaRkqD8,18811
25
- continuo_python_runtime-0.4.1.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
26
- continuo_python_runtime-0.4.1.dist-info/entry_points.txt,sha256=ZvIwSm9f9B9ZmZMf6CyF5Zt4QONn8rqaIk-u-B1CF2Y,70
27
- continuo_python_runtime-0.4.1.dist-info/licenses/LICENSE,sha256=hfXfFCk-8gnps4YvHA6bjCNaSYqOrq2gAdqkXYycAQc,11345
28
- continuo_python_runtime-0.4.1.dist-info/licenses/NOTICE,sha256=ykgYyQkAMx3uas90FZHzt0aTca9IgJQCLpZ4d74Pl3U,465
29
- continuo_python_runtime-0.4.1.dist-info/RECORD,,
24
+ continuo_python_runtime-0.5.0.dist-info/METADATA,sha256=vQisnCASgreJNhw4ryPWuyQvo4dmw6mWEMJH3zZxHx4,18811
25
+ continuo_python_runtime-0.5.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
26
+ continuo_python_runtime-0.5.0.dist-info/entry_points.txt,sha256=ZvIwSm9f9B9ZmZMf6CyF5Zt4QONn8rqaIk-u-B1CF2Y,70
27
+ continuo_python_runtime-0.5.0.dist-info/licenses/LICENSE,sha256=hfXfFCk-8gnps4YvHA6bjCNaSYqOrq2gAdqkXYycAQc,11345
28
+ continuo_python_runtime-0.5.0.dist-info/licenses/NOTICE,sha256=ykgYyQkAMx3uas90FZHzt0aTca9IgJQCLpZ4d74Pl3U,465
29
+ continuo_python_runtime-0.5.0.dist-info/RECORD,,