databuck-sdk 0.5.46__tar.gz

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.
@@ -0,0 +1,3 @@
1
+ include README.md
2
+ include RELEASING.md
3
+ global-exclude *.jar
@@ -0,0 +1,354 @@
1
+ Metadata-Version: 2.4
2
+ Name: databuck-sdk
3
+ Version: 0.5.46
4
+ Summary: DataBuck data quality SDK for PySpark and Databricks
5
+ Author: DataBuck
6
+ Project-URL: Repository, https://github.com/FirstEigen-Labs/databuck_sdk
7
+ Keywords: data quality,databricks,pyspark,data profiling
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Database
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: google-genai>=1.0.0
19
+
20
+ # databuck-sdk
21
+
22
+ Python wrapper for the DataBuck Spark SDK. It discovers data-quality rules from
23
+ an existing Spark DataFrame or a registered Spark table and exports expectations
24
+ that Databricks Lakeflow Declarative Pipelines can execute before downstream
25
+ data is published.
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ python -m pip install databuck-sdk
31
+ python -c "import databuck"
32
+ ```
33
+
34
+ If `databuck-spark-sdk` is installed, remove it before installing this package;
35
+ both distributions provide the same `databuck` Python import:
36
+
37
+ ```bash
38
+ python -m pip uninstall databuck-spark-sdk
39
+ python -m pip install --upgrade databuck-sdk
40
+ ```
41
+
42
+ Importing `databuck` downloads `databuck-spark-sdk.jar` from the DataBuck S3
43
+ URL to `databuck/jars/` in the installed Python package, with progress output.
44
+ The downloaded path is set in `DATABUCK_SPARK_SDK_JAR` for the current Python
45
+ process. A later import reuses the existing JAR.
46
+ The JAR is not included in the wheel because it exceeds PyPI's
47
+ default per-file upload limit. An internet connection and write access to the
48
+ installed package directory are required for the first download.
49
+
50
+ `python -m databuck` is an explicit download command that also prints the
51
+ local path. Set `DATABUCK_SPARK_SDK_AUTO_DOWNLOAD=0` before import to defer the
52
+ download when offline. `DataBuck.jar_path()` returns the path after download.
53
+ Downloading the JAR does not install it as a Databricks compute library.
54
+
55
+ To use an existing JAR or another writable destination, set
56
+ `DATABUCK_SPARK_SDK_JAR` to that file path. If the download URL changes, set
57
+ `DATABUCK_SPARK_SDK_JAR_URL` to the new HTTPS URL before importing or running
58
+ `python -m databuck`. The download is checked against
59
+ the published JAR's SHA-256 hash. If the JAR content changes, publish a new
60
+ Python package version with its new hash, or set
61
+ `DATABUCK_SPARK_SDK_JAR_SHA256` to the expected hash.
62
+
63
+ ### Databricks notebook setup
64
+
65
+ Run this once in the notebook to install the Python package:
66
+
67
+ ```python
68
+ %pip install databuck-sdk
69
+ ```
70
+
71
+ After installing or upgrading, restart Python in the next cell so the notebook
72
+ loads the new package version:
73
+
74
+ ```python
75
+ dbutils.library.restartPython()
76
+ ```
77
+
78
+ Then verify the version and set a writable Unity Catalog Volume **file path**
79
+ before importing `databuck`:
80
+
81
+ ```python
82
+ import os
83
+ from importlib.metadata import version
84
+
85
+ print(version("databuck-sdk"))
86
+
87
+ os.environ["DATABUCK_SPARK_SDK_JAR"] = (
88
+ "/Volumes/catalog/schema/volume/databuck-spark-sdk.jar"
89
+ )
90
+
91
+ from databuck import DataBuck # Downloads the JAR to that path on first import.
92
+
93
+ print(DataBuck.jar_path())
94
+ ```
95
+
96
+ Use the full filename ending in `.jar`, not just the Volume directory. Importing
97
+ `databuck` downloads or reuses the JAR at that path. Setting the variable after
98
+ the import is too late to choose the initial download location. A Volume keeps
99
+ the JAR available beyond the current notebook driver session.
100
+
101
+ Before calling `DataBuck.discover(...)`, attach the downloaded JAR to the
102
+ **compute that runs discovery**: in Databricks, open **Compute** > select that
103
+ compute > **Libraries** > **Install New**, select the Volume as the library
104
+ source, choose the JAR path printed above, and install it. If the compute is
105
+ already running, restart it or reattach the notebook so Spark loads the new
106
+ library. Then read your Spark DataFrame and run the discovery example below.
107
+ The Python import downloads the file; it does not attach the JAR to compute.
108
+ See [Databricks compute-scoped library instructions](https://docs.databricks.com/aws/en/libraries/cluster-libraries).
109
+
110
+ ## Local PySpark usage
111
+
112
+ ```python
113
+ from pyspark.sql import SparkSession
114
+ import os
115
+
116
+ from databuck import DataBuck
117
+
118
+ spark = (
119
+ SparkSession.builder
120
+ .config("spark.jars", DataBuck.jar_path())
121
+ .getOrCreate()
122
+ )
123
+
124
+ df = spark.read.csv("customers.csv", header=True)
125
+
126
+ print(DataBuck.count(df))
127
+ ```
128
+
129
+ ## Discover and export rules for Databricks
130
+
131
+ Run discovery in a Databricks notebook or Spark job against an existing DataFrame,
132
+ or pass a Spark table name and the SDK will read it into a DataFrame internally.
133
+ Pass PDF and DOCX policy files for context-aware BuckGPT rules.
134
+ The SDK exports generated rules as JSON (`.json`) or YAML (`.yaml` / `.yml`).
135
+ A Lakeflow Declarative Pipeline then loads and executes those rules as
136
+ expectations. Choose one of the two JSON inputs below; both use the same
137
+ discovery and export flow. The YAML workflow appears below.
138
+
139
+ ```python
140
+ from databuck import DataBuck
141
+
142
+ context = {
143
+ "gemini_api_key": "YOUR_GEMINI_API_KEY",
144
+ "domain_name": "banking",
145
+ "pdf_paths": [
146
+ "/Volumes/catalog/schema/volume/customer_policy.pdf",
147
+ "/Volumes/catalog/schema/volume/data_contract.docx",
148
+ ],
149
+ }
150
+
151
+ # Option 1: use a DataFrame already available in your pipeline.
152
+ json_path = DataBuck.discover(
153
+ df, "/Volumes/catalog/schema/volume/expectations.json", context=context
154
+ )
155
+ print(json_path)
156
+ ```
157
+
158
+ Or pass a registered Spark table name. The SDK calls `spark.read.table(...)`
159
+ internally, then passes that DataFrame through the same discovery and export:
160
+
161
+ ```python
162
+ json_path = DataBuck.discover(
163
+ "catalog.schema.telco_customer_subscription",
164
+ "/Volumes/catalog/schema/volume/expectations.json",
165
+ context=context,
166
+ )
167
+ print(json_path)
168
+ ```
169
+
170
+ Replace the example Volume paths and table name with files and a table available
171
+ in your workspace. The table-name option uses the notebook's Spark session and
172
+ requires read access to the registered table; it does not take separate database
173
+ connection details. Passing an existing DataFrame avoids reading the table again.
174
+
175
+ The call combines automatic and policy-informed rules. The output extension
176
+ selects JSON or YAML. With `domain_name`, JSON and YAML contain selected HIGH
177
+ and MEDIUM rules from both sources. The SDK writes `*_all_rules.csv` for review
178
+ and `*_high_medium_rules.csv` beside the output file for the selected rules.
179
+ The selected-rules CSV includes rule names, expressions, sources, and
180
+ priorities.
181
+
182
+ `pdf_paths` accepts PDF and DOCX files available to the notebook. For a
183
+ dataset-level uniqueness rule, the output includes a `dataset_checks` section.
184
+ Run its SQL against the full dataset separately, replacing `{{DATAFRAME}}` with
185
+ your source table or view. Dataset checks are not Lakeflow row expectations.
186
+
187
+ To export only automatic profiling rules, omit `context`:
188
+
189
+ ```python
190
+ json_path = DataBuck.discover(
191
+ df, "/Volumes/catalog/schema/volume/expectations.json"
192
+ )
193
+ ```
194
+
195
+ Without context, the output contains automatic rules and JSON places them in
196
+ the `warn` group. To include policy-informed rules, pass a business statement
197
+ or policy document along with the Gemini API key.
198
+
199
+ The JSON contains three action dictionaries: `warn`, `drop`, and `fail`.
200
+ In a Databricks Lakeflow Declarative Pipeline, use the dictionaries with
201
+ `dp.expect_all`, `dp.expect_all_or_drop`, and `dp.expect_all_or_fail`,
202
+ respectively.
203
+
204
+ For example, add this to the Lakeflow Declarative Pipeline source file. The
205
+ expectations run when the pipeline updates; the SDK's discovery call above
206
+ generates the file beforehand:
207
+
208
+ ```python
209
+ import json
210
+ from pyspark import pipelines as dp
211
+
212
+ with open("/Volumes/catalog/schema/volume/expectations.json", encoding="utf-8") as stream:
213
+ expectations = json.load(stream)
214
+
215
+ @dp.materialized_view(name="telco_customers_checked")
216
+ @dp.expect_all(expectations["warn"])
217
+ @dp.expect_all_or_drop(expectations["drop"])
218
+ @dp.expect_all_or_fail(expectations["fail"])
219
+ def customers_checked():
220
+ return spark.read.table("catalog.schema.telco_customer_subscription")
221
+ ```
222
+
223
+ ### What the pipeline results look like
224
+
225
+ `DataBuck.discover(df, output_path, ...)` prints the rules and returns the path to the rules
226
+ file. The row results appear **after the Lakeflow Declarative Pipeline runs**,
227
+ in the validated table's **Expectations** view. For example, one telco demo run
228
+ showed:
229
+
230
+ | Pipeline result | Records |
231
+ | --- | ---: |
232
+ | Written | 58 (58%) |
233
+ | Dropped | 42 (42%) |
234
+
235
+ | Expectation | Action shown in Databricks | Failed records |
236
+ | --- | --- | ---: |
237
+ | `BuckGPT_Rule_006` | ALLOW | 60 |
238
+ | `BuckGPT_Rule_007` | DROP | 40 |
239
+ | `BuckGPT_Rule_009` | DROP | 20 |
240
+ | `valid_length_network_type` | DROP | 4 |
241
+ | `valid_pattern_network_type` | DROP | 4 |
242
+
243
+ `ALLOW` corresponds to `dp.expect_all`: the violation is recorded without
244
+ dropping the row. `DROP` corresponds to `dp.expect_all_or_drop`: invalid rows
245
+ are excluded from the validated output. A `FAIL` expectation stops the pipeline
246
+ update when violated. A row can fail more than one rule, so the per-rule failed
247
+ record counts do not add up to the dropped-row total. These numbers are from one
248
+ demo update; actual results depend on the source data and exported rules.
249
+
250
+ The pipeline must read a DataFrame with the columns used by the exported
251
+ expectations. Regenerate the rules file when the source schema or business
252
+ policy changes, then refresh the pipeline.
253
+
254
+ ```json
255
+ {
256
+ "warn": {"not_null_customer_email": "`customer_email` IS NOT NULL"},
257
+ "drop": {"not_null_order_id": "`order_id` IS NOT NULL"},
258
+ "fail": {"valid_pattern_currency_code": "`currency_code` IS NULL OR CAST(`currency_code` AS STRING) RLIKE '(?:^[A-Z][A-Z][A-Z]$)'"}
259
+ }
260
+ ```
261
+
262
+ The example shows the file shape; actual actions depend on the generated rules.
263
+
264
+ ## Export flat YAML expectations
265
+
266
+ Pass a `.yaml` or `.yml` output file to write a flat YAML document. Pass either
267
+ an existing DataFrame or a table name. Choose one of these calls:
268
+
269
+ ```python
270
+ from databuck import DataBuck
271
+
272
+ context = {
273
+ "gemini_api_key": "YOUR_GEMINI_API_KEY",
274
+ "pdf_paths": [
275
+ "/Volumes/catalog/schema/volume/customer_policy.pdf",
276
+ "/Volumes/catalog/schema/volume/data_contract.docx",
277
+ ],
278
+ }
279
+
280
+ # Option 1: use a DataFrame already available in your pipeline.
281
+ yaml_path = DataBuck.discover(
282
+ df,
283
+ "/Volumes/catalog/schema/volume/telco_expectations.yaml",
284
+ context=context,
285
+ )
286
+ print(yaml_path)
287
+ ```
288
+
289
+ Or pass a registered Spark table name. The SDK reads it into a DataFrame
290
+ internally before discovering and exporting the rules:
291
+
292
+ ```python
293
+ yaml_path = DataBuck.discover(
294
+ "catalog.schema.telco_customer_subscription",
295
+ "/Volumes/catalog/schema/volume/telco_expectations.yaml",
296
+ context=context,
297
+ )
298
+ print(yaml_path)
299
+ ```
300
+
301
+ No separate `table_name=` argument is needed. When you pass a table name, YAML
302
+ includes a `table:` field. When you pass a DataFrame, YAML contains
303
+ `expectations:` without a `table:` field because the original table name is
304
+ not reliably available from a DataFrame.
305
+
306
+ For example, the generated file has this shape (the names and SQL depend on the
307
+ discovered rules):
308
+
309
+ ```yaml
310
+ table: catalog.schema.telco_customer_subscription
311
+
312
+ expectations:
313
+ not_null_subscriber_id: "`subscriber_id` IS NOT NULL"
314
+ BuckGPT_Rule_001: "NOT COALESCE((subscription_status_cd = 'INVALID'), FALSE)"
315
+ ```
316
+
317
+ YAML combines automatic and policy-informed rules under `expectations` without
318
+ `warn`, `drop`, or `fail` groups. It does not call the action classifier. Use
319
+ JSON when the pipeline needs those action groups.
320
+ Omit `context` to write only automatically discovered rules.
321
+
322
+ To run the flat YAML expectations in a Lakeflow Declarative Pipeline, add
323
+ `PyYAML` to the pipeline's Python dependencies and load the `expectations`
324
+ mapping:
325
+
326
+ ```python
327
+ import yaml
328
+ from pyspark import pipelines as dp
329
+
330
+ with open("/Volumes/catalog/schema/volume/telco_expectations.yaml", encoding="utf-8") as stream:
331
+ rules_doc = yaml.safe_load(stream)
332
+
333
+ source_table = rules_doc.get("table") or "catalog.schema.telco_customer_subscription"
334
+
335
+ @dp.materialized_view(name="telco_customers_checked")
336
+ @dp.expect_all(rules_doc["expectations"])
337
+ def telco_customers_checked():
338
+ return spark.read.table(source_table)
339
+ ```
340
+
341
+ If you discovered from a DataFrame, set the fallback `source_table` to the
342
+ table or transformation that produces the same columns and rows.
343
+
344
+ In this example, YAML rules are monitored with `dp.expect_all`: invalid rows
345
+ remain in the output and their failures are recorded. Use the action-grouped
346
+ JSON format if rules must drop rows or fail the pipeline update.
347
+
348
+ `DataBuck.discover_rules(df)` still returns automatic profiling rules without
349
+ exporting. For compatibility, `DataBuck.discover(df, context_dict)` still
350
+ returns BuckGPT rules without exporting. Pass an output file path as the second
351
+ argument to `DataBuck.discover(...)` to combine discovery and export.
352
+
353
+ In JSON, each action dictionary maps expectation names to Spark SQL pass
354
+ conditions, such as `{"not_null_subscriber_id": "`subscriber_id` IS NOT NULL"}`.
@@ -0,0 +1,335 @@
1
+ # databuck-sdk
2
+
3
+ Python wrapper for the DataBuck Spark SDK. It discovers data-quality rules from
4
+ an existing Spark DataFrame or a registered Spark table and exports expectations
5
+ that Databricks Lakeflow Declarative Pipelines can execute before downstream
6
+ data is published.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ python -m pip install databuck-sdk
12
+ python -c "import databuck"
13
+ ```
14
+
15
+ If `databuck-spark-sdk` is installed, remove it before installing this package;
16
+ both distributions provide the same `databuck` Python import:
17
+
18
+ ```bash
19
+ python -m pip uninstall databuck-spark-sdk
20
+ python -m pip install --upgrade databuck-sdk
21
+ ```
22
+
23
+ Importing `databuck` downloads `databuck-spark-sdk.jar` from the DataBuck S3
24
+ URL to `databuck/jars/` in the installed Python package, with progress output.
25
+ The downloaded path is set in `DATABUCK_SPARK_SDK_JAR` for the current Python
26
+ process. A later import reuses the existing JAR.
27
+ The JAR is not included in the wheel because it exceeds PyPI's
28
+ default per-file upload limit. An internet connection and write access to the
29
+ installed package directory are required for the first download.
30
+
31
+ `python -m databuck` is an explicit download command that also prints the
32
+ local path. Set `DATABUCK_SPARK_SDK_AUTO_DOWNLOAD=0` before import to defer the
33
+ download when offline. `DataBuck.jar_path()` returns the path after download.
34
+ Downloading the JAR does not install it as a Databricks compute library.
35
+
36
+ To use an existing JAR or another writable destination, set
37
+ `DATABUCK_SPARK_SDK_JAR` to that file path. If the download URL changes, set
38
+ `DATABUCK_SPARK_SDK_JAR_URL` to the new HTTPS URL before importing or running
39
+ `python -m databuck`. The download is checked against
40
+ the published JAR's SHA-256 hash. If the JAR content changes, publish a new
41
+ Python package version with its new hash, or set
42
+ `DATABUCK_SPARK_SDK_JAR_SHA256` to the expected hash.
43
+
44
+ ### Databricks notebook setup
45
+
46
+ Run this once in the notebook to install the Python package:
47
+
48
+ ```python
49
+ %pip install databuck-sdk
50
+ ```
51
+
52
+ After installing or upgrading, restart Python in the next cell so the notebook
53
+ loads the new package version:
54
+
55
+ ```python
56
+ dbutils.library.restartPython()
57
+ ```
58
+
59
+ Then verify the version and set a writable Unity Catalog Volume **file path**
60
+ before importing `databuck`:
61
+
62
+ ```python
63
+ import os
64
+ from importlib.metadata import version
65
+
66
+ print(version("databuck-sdk"))
67
+
68
+ os.environ["DATABUCK_SPARK_SDK_JAR"] = (
69
+ "/Volumes/catalog/schema/volume/databuck-spark-sdk.jar"
70
+ )
71
+
72
+ from databuck import DataBuck # Downloads the JAR to that path on first import.
73
+
74
+ print(DataBuck.jar_path())
75
+ ```
76
+
77
+ Use the full filename ending in `.jar`, not just the Volume directory. Importing
78
+ `databuck` downloads or reuses the JAR at that path. Setting the variable after
79
+ the import is too late to choose the initial download location. A Volume keeps
80
+ the JAR available beyond the current notebook driver session.
81
+
82
+ Before calling `DataBuck.discover(...)`, attach the downloaded JAR to the
83
+ **compute that runs discovery**: in Databricks, open **Compute** > select that
84
+ compute > **Libraries** > **Install New**, select the Volume as the library
85
+ source, choose the JAR path printed above, and install it. If the compute is
86
+ already running, restart it or reattach the notebook so Spark loads the new
87
+ library. Then read your Spark DataFrame and run the discovery example below.
88
+ The Python import downloads the file; it does not attach the JAR to compute.
89
+ See [Databricks compute-scoped library instructions](https://docs.databricks.com/aws/en/libraries/cluster-libraries).
90
+
91
+ ## Local PySpark usage
92
+
93
+ ```python
94
+ from pyspark.sql import SparkSession
95
+ import os
96
+
97
+ from databuck import DataBuck
98
+
99
+ spark = (
100
+ SparkSession.builder
101
+ .config("spark.jars", DataBuck.jar_path())
102
+ .getOrCreate()
103
+ )
104
+
105
+ df = spark.read.csv("customers.csv", header=True)
106
+
107
+ print(DataBuck.count(df))
108
+ ```
109
+
110
+ ## Discover and export rules for Databricks
111
+
112
+ Run discovery in a Databricks notebook or Spark job against an existing DataFrame,
113
+ or pass a Spark table name and the SDK will read it into a DataFrame internally.
114
+ Pass PDF and DOCX policy files for context-aware BuckGPT rules.
115
+ The SDK exports generated rules as JSON (`.json`) or YAML (`.yaml` / `.yml`).
116
+ A Lakeflow Declarative Pipeline then loads and executes those rules as
117
+ expectations. Choose one of the two JSON inputs below; both use the same
118
+ discovery and export flow. The YAML workflow appears below.
119
+
120
+ ```python
121
+ from databuck import DataBuck
122
+
123
+ context = {
124
+ "gemini_api_key": "YOUR_GEMINI_API_KEY",
125
+ "domain_name": "banking",
126
+ "pdf_paths": [
127
+ "/Volumes/catalog/schema/volume/customer_policy.pdf",
128
+ "/Volumes/catalog/schema/volume/data_contract.docx",
129
+ ],
130
+ }
131
+
132
+ # Option 1: use a DataFrame already available in your pipeline.
133
+ json_path = DataBuck.discover(
134
+ df, "/Volumes/catalog/schema/volume/expectations.json", context=context
135
+ )
136
+ print(json_path)
137
+ ```
138
+
139
+ Or pass a registered Spark table name. The SDK calls `spark.read.table(...)`
140
+ internally, then passes that DataFrame through the same discovery and export:
141
+
142
+ ```python
143
+ json_path = DataBuck.discover(
144
+ "catalog.schema.telco_customer_subscription",
145
+ "/Volumes/catalog/schema/volume/expectations.json",
146
+ context=context,
147
+ )
148
+ print(json_path)
149
+ ```
150
+
151
+ Replace the example Volume paths and table name with files and a table available
152
+ in your workspace. The table-name option uses the notebook's Spark session and
153
+ requires read access to the registered table; it does not take separate database
154
+ connection details. Passing an existing DataFrame avoids reading the table again.
155
+
156
+ The call combines automatic and policy-informed rules. The output extension
157
+ selects JSON or YAML. With `domain_name`, JSON and YAML contain selected HIGH
158
+ and MEDIUM rules from both sources. The SDK writes `*_all_rules.csv` for review
159
+ and `*_high_medium_rules.csv` beside the output file for the selected rules.
160
+ The selected-rules CSV includes rule names, expressions, sources, and
161
+ priorities.
162
+
163
+ `pdf_paths` accepts PDF and DOCX files available to the notebook. For a
164
+ dataset-level uniqueness rule, the output includes a `dataset_checks` section.
165
+ Run its SQL against the full dataset separately, replacing `{{DATAFRAME}}` with
166
+ your source table or view. Dataset checks are not Lakeflow row expectations.
167
+
168
+ To export only automatic profiling rules, omit `context`:
169
+
170
+ ```python
171
+ json_path = DataBuck.discover(
172
+ df, "/Volumes/catalog/schema/volume/expectations.json"
173
+ )
174
+ ```
175
+
176
+ Without context, the output contains automatic rules and JSON places them in
177
+ the `warn` group. To include policy-informed rules, pass a business statement
178
+ or policy document along with the Gemini API key.
179
+
180
+ The JSON contains three action dictionaries: `warn`, `drop`, and `fail`.
181
+ In a Databricks Lakeflow Declarative Pipeline, use the dictionaries with
182
+ `dp.expect_all`, `dp.expect_all_or_drop`, and `dp.expect_all_or_fail`,
183
+ respectively.
184
+
185
+ For example, add this to the Lakeflow Declarative Pipeline source file. The
186
+ expectations run when the pipeline updates; the SDK's discovery call above
187
+ generates the file beforehand:
188
+
189
+ ```python
190
+ import json
191
+ from pyspark import pipelines as dp
192
+
193
+ with open("/Volumes/catalog/schema/volume/expectations.json", encoding="utf-8") as stream:
194
+ expectations = json.load(stream)
195
+
196
+ @dp.materialized_view(name="telco_customers_checked")
197
+ @dp.expect_all(expectations["warn"])
198
+ @dp.expect_all_or_drop(expectations["drop"])
199
+ @dp.expect_all_or_fail(expectations["fail"])
200
+ def customers_checked():
201
+ return spark.read.table("catalog.schema.telco_customer_subscription")
202
+ ```
203
+
204
+ ### What the pipeline results look like
205
+
206
+ `DataBuck.discover(df, output_path, ...)` prints the rules and returns the path to the rules
207
+ file. The row results appear **after the Lakeflow Declarative Pipeline runs**,
208
+ in the validated table's **Expectations** view. For example, one telco demo run
209
+ showed:
210
+
211
+ | Pipeline result | Records |
212
+ | --- | ---: |
213
+ | Written | 58 (58%) |
214
+ | Dropped | 42 (42%) |
215
+
216
+ | Expectation | Action shown in Databricks | Failed records |
217
+ | --- | --- | ---: |
218
+ | `BuckGPT_Rule_006` | ALLOW | 60 |
219
+ | `BuckGPT_Rule_007` | DROP | 40 |
220
+ | `BuckGPT_Rule_009` | DROP | 20 |
221
+ | `valid_length_network_type` | DROP | 4 |
222
+ | `valid_pattern_network_type` | DROP | 4 |
223
+
224
+ `ALLOW` corresponds to `dp.expect_all`: the violation is recorded without
225
+ dropping the row. `DROP` corresponds to `dp.expect_all_or_drop`: invalid rows
226
+ are excluded from the validated output. A `FAIL` expectation stops the pipeline
227
+ update when violated. A row can fail more than one rule, so the per-rule failed
228
+ record counts do not add up to the dropped-row total. These numbers are from one
229
+ demo update; actual results depend on the source data and exported rules.
230
+
231
+ The pipeline must read a DataFrame with the columns used by the exported
232
+ expectations. Regenerate the rules file when the source schema or business
233
+ policy changes, then refresh the pipeline.
234
+
235
+ ```json
236
+ {
237
+ "warn": {"not_null_customer_email": "`customer_email` IS NOT NULL"},
238
+ "drop": {"not_null_order_id": "`order_id` IS NOT NULL"},
239
+ "fail": {"valid_pattern_currency_code": "`currency_code` IS NULL OR CAST(`currency_code` AS STRING) RLIKE '(?:^[A-Z][A-Z][A-Z]$)'"}
240
+ }
241
+ ```
242
+
243
+ The example shows the file shape; actual actions depend on the generated rules.
244
+
245
+ ## Export flat YAML expectations
246
+
247
+ Pass a `.yaml` or `.yml` output file to write a flat YAML document. Pass either
248
+ an existing DataFrame or a table name. Choose one of these calls:
249
+
250
+ ```python
251
+ from databuck import DataBuck
252
+
253
+ context = {
254
+ "gemini_api_key": "YOUR_GEMINI_API_KEY",
255
+ "pdf_paths": [
256
+ "/Volumes/catalog/schema/volume/customer_policy.pdf",
257
+ "/Volumes/catalog/schema/volume/data_contract.docx",
258
+ ],
259
+ }
260
+
261
+ # Option 1: use a DataFrame already available in your pipeline.
262
+ yaml_path = DataBuck.discover(
263
+ df,
264
+ "/Volumes/catalog/schema/volume/telco_expectations.yaml",
265
+ context=context,
266
+ )
267
+ print(yaml_path)
268
+ ```
269
+
270
+ Or pass a registered Spark table name. The SDK reads it into a DataFrame
271
+ internally before discovering and exporting the rules:
272
+
273
+ ```python
274
+ yaml_path = DataBuck.discover(
275
+ "catalog.schema.telco_customer_subscription",
276
+ "/Volumes/catalog/schema/volume/telco_expectations.yaml",
277
+ context=context,
278
+ )
279
+ print(yaml_path)
280
+ ```
281
+
282
+ No separate `table_name=` argument is needed. When you pass a table name, YAML
283
+ includes a `table:` field. When you pass a DataFrame, YAML contains
284
+ `expectations:` without a `table:` field because the original table name is
285
+ not reliably available from a DataFrame.
286
+
287
+ For example, the generated file has this shape (the names and SQL depend on the
288
+ discovered rules):
289
+
290
+ ```yaml
291
+ table: catalog.schema.telco_customer_subscription
292
+
293
+ expectations:
294
+ not_null_subscriber_id: "`subscriber_id` IS NOT NULL"
295
+ BuckGPT_Rule_001: "NOT COALESCE((subscription_status_cd = 'INVALID'), FALSE)"
296
+ ```
297
+
298
+ YAML combines automatic and policy-informed rules under `expectations` without
299
+ `warn`, `drop`, or `fail` groups. It does not call the action classifier. Use
300
+ JSON when the pipeline needs those action groups.
301
+ Omit `context` to write only automatically discovered rules.
302
+
303
+ To run the flat YAML expectations in a Lakeflow Declarative Pipeline, add
304
+ `PyYAML` to the pipeline's Python dependencies and load the `expectations`
305
+ mapping:
306
+
307
+ ```python
308
+ import yaml
309
+ from pyspark import pipelines as dp
310
+
311
+ with open("/Volumes/catalog/schema/volume/telco_expectations.yaml", encoding="utf-8") as stream:
312
+ rules_doc = yaml.safe_load(stream)
313
+
314
+ source_table = rules_doc.get("table") or "catalog.schema.telco_customer_subscription"
315
+
316
+ @dp.materialized_view(name="telco_customers_checked")
317
+ @dp.expect_all(rules_doc["expectations"])
318
+ def telco_customers_checked():
319
+ return spark.read.table(source_table)
320
+ ```
321
+
322
+ If you discovered from a DataFrame, set the fallback `source_table` to the
323
+ table or transformation that produces the same columns and rows.
324
+
325
+ In this example, YAML rules are monitored with `dp.expect_all`: invalid rows
326
+ remain in the output and their failures are recorded. Use the action-grouped
327
+ JSON format if rules must drop rows or fail the pipeline update.
328
+
329
+ `DataBuck.discover_rules(df)` still returns automatic profiling rules without
330
+ exporting. For compatibility, `DataBuck.discover(df, context_dict)` still
331
+ returns BuckGPT rules without exporting. Pass an output file path as the second
332
+ argument to `DataBuck.discover(...)` to combine discovery and export.
333
+
334
+ In JSON, each action dictionary maps expectation names to Spark SQL pass
335
+ conditions, such as `{"not_null_subscriber_id": "`subscriber_id` IS NOT NULL"}`.