Skip to main content

dscribe-dq

Run dScribe data quality rules against your Databricks or MSSQL databases and write the results back to dScribe.

For library internals, architecture, and contributing, see DEVELOPMENT.md.

Prerequisites

  • A dScribe account with at least one asset that has data quality rules defined in its ODCS spec
  • Your dScribe API key (Settings → API keys in the dScribe UI)
  • The asset UUID you want to validate
  • Access to the database the rules target (Databricks or MSSQL)

Installation

pip install dscribe-dq

How it works

Initialize DScribeDQ once with your credentials, then call run_validation with a list of post-processors. Post-processors are small pipeline steps that run in order after validation — writing results back to dScribe, uploading failed-row CSVs, generating reports, etc.

DScribeDQ(credentials) → dq.run_validation(connector_config, postprocessors=[...])

The only post-processor built into the SDK is write_back_to_dscribe, which posts pass/fail results to dScribe so the asset's quality status updates in the UI.

Quickstart

1. Find your asset ID and API key

In the dScribe UI, open the asset you want to validate. The asset ID is the UUID in the URL:

https://app.dscribe.cloud/catalog/assets/337eaa9e-47ed-4b37-a124-050d4932a520
                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Your API key is under Settings → API keys.

2. Run validation and write back to dScribe

from dscribe_dq import DScribeDQ

dq = DScribeDQ(
    api_key="<your-api-key>",
    base_url="https://app.dscribe.cloud/catalog/api",
    asset_id="337eaa9e-47ed-4b37-a124-050d4932a520",
)

ctx = dq.run_validation(
    source_configs={
        # key must match the server id in the ODCS servers block
        "09bcc0f9-9d21-460d-9cb9-942b00e360bf": {
            "type": "databricks",
            "host": "adb-858283489583940.0.azuredatabricks.net",
            "client_id": "<client-id>",
            "client_secret": "<client-secret>",
            "tenant_id": "<tenant-id>",
            "http_path": "/sql/1.0/warehouses/abc123def456",
            "catalog": "hive_metastore",   # optional
            "schema": "default",           # optional
        }
    },
    postprocessors=[dq.write_back_to_dscribe()],
)

Each rule in dScribe gets a lastCheckStatus (passed or failed), lastCheckTimestamp, and failure metrics added to its customProperties after the pipeline runs.

Databricks notebook

%pip install dscribe-dq
from dscribe_dq import DScribeDQ

dq = DScribeDQ(
    api_key=dbutils.secrets.get(scope="dscribe-dq", key="DSCRIBE_API_KEY"),
    base_url="https://app.dscribe.cloud/catalog/api",
    asset_id="<your-asset-uuid>",
)

ctx = dq.run_validation(
    source_configs={
        "<server-id>": {
            "type": "databricks",
            "host": spark.conf.get("spark.databricks.workspaceUrl"),
            "client_id": dbutils.secrets.get(scope="dscribe-dq", key="CLIENT_ID"),
            "client_secret": dbutils.secrets.get(scope="dscribe-dq", key="CLIENT_SECRET"),
            "tenant_id": dbutils.secrets.get(scope="dscribe-dq", key="TENANT_ID"),
            "http_path": "/sql/1.0/warehouses/<warehouse-id>",
        }
    },
    postprocessors=[dq.write_back_to_dscribe()],
)

The http_path can be found in the Databricks UI under SQL Warehouses → your warehouse → Connection details.

Connecting to MSSQL

SQL Server authentication:

source_configs={
    "<server-id>": {
        "type": "sqlserver",
        "host": "your-server.database.windows.net",
        "database": "your-db",
        "schema": "SalesLT",
        "authentication": "SQL Server",
        "username": "your-user",
        "password": "your-password",
    }
}

Entra ID (service principal) authentication:

source_configs={
    "<server-id>": {
        "type": "sqlserver",
        "host": "your-server.database.windows.net",
        "database": "your-db",
        "schema": "SalesLT",
        "authentication": "Entra ID",
        "tenant_id": "<tenant-id>",
        "client_id": "<client-id>",
        "client_secret": "<client-secret>",
    }
}

Multiple sources in one call

If your asset has rules targeting both Databricks and MSSQL, pass both in source_configs. Rules are automatically grouped by source and run independently:

source_configs={
    "<mssql-server-id>": {"type": "sqlserver", ...},
    "<databricks-server-id>": {"type": "databricks", ...},
}

CI/CD usage (env vars)

For automated pipelines, set env vars and call the module-level run_validation directly:

DSCRIBE_API_KEY=...
DSCRIBE_ASSET_ID=...
DSCRIBE_BASE_URL=...
DATABRICKS_HOST=...
DATABRICKS_CLIENT_ID=...
DATABRICKS_CLIENT_SECRET=...
DATABRICKS_TENANT_ID=...
DATABRICKS_HTTP_PATH=...
from dscribe_dq import run_validation

ctx = run_validation()  # reads all config from env vars

Post-processors

Post-processors provide a way to perform additional processing after validation has completed. They receive the validation context (ctx) and can inspect or modify the results before the run finishes.

Pass them to run_validation in the order you want them to run:

ctx = dq.run_validation(
    source_configs={...},
    postprocessors=[
        dq.write_back_to_dscribe(),
    ],
)

Built-in: write_back_to_dscribe

write_back_to_dscribe is the built-in post-processor. It sends each rule's validation result back to dScribe so the latest status is visible in the dScribe UI.

postprocessors=[
    dq.write_back_to_dscribe(),
]

For each rule, it sends:

  • lastCheckStatus
  • lastCheckTimestamp
  • lastCheckDetails — a structured object with success_percent, unexpected_percent, unexpected_count, and element_count, generated automatically from ctx.results. You do not need to set these yourself.

lastCheckDetails can also carry two optional links, but only if an earlier post-processor sets them first:

lastCheckDetails field Set by a post-processor via Used for
failed_rows_url res["csv_url"] Link to the failing rows for a rule
report_url ctx.report_url Link to a report for the full validation run

If they are not set, write_back_to_dscribe still writes the validation results normally — add a custom post-processor before it that uploads the relevant files and sets these values, as shown in Custom post-processors.

The ctx object

Every post-processor receives the same DQContext.

The most useful fields are:

Field Description
ctx.results Validation results, one entry per rule
ctx.asset_id ID of the asset being validated
ctx.odcs Parsed ODCS contract used for validation
ctx.timestamp UTC timestamp for the start of the run
ctx.audience Contract audience, if one was selected
ctx.profile Profiling results when enable_profiling=True
ctx.report_url Optional report URL that can be set by a post-processor

Each entry in ctx.results looks like this:

{
    "rule_id": "675dbbcd-ee5c-45bc-85b7-34514beaea73",
    "expectation": "unexpected_rows_expectation",
    "column": "NATIONALITY_ID",
    "success": False,
    "result": {...},
    "failed_rows": [
        {"ID": "...", "NATIONALITY_ID": None},
        ...
    ],
}

For most custom post-processors, these fields are enough:

  • rule_id — ID of the dScribe rule
  • column — column checked by the rule, or "table" for table-level rules
  • success — whether the rule passed
  • failed_rows — collected rows that failed the rule

result contains the raw Great Expectations validation result and is available when you need more detailed validation information.

When profiling is enabled with enable_profiling=True, profiling data is available through ctx.profile:

{
    "__table__": {
        "row_count": 2672186
    },
    "NATIONALITY_ID": {
        "type": "categorical",
        "null_count": 12,
        "distinct_count": 4,
        "value_counts": [...]
    },
    "AGE": {
        "type": "numeric",
        "null_count": 0,
        "distinct_count": 90,
        "mean": 41.2,
        "min": 0,
        "max": 120,
        "quantiles": [0, 22, 41, 60, 120]
    },
}

Custom post-processors

A custom post-processor is simply a function that accepts ctx.

For example, to log the failing rows:

def log_failed_rows(ctx):
    for res in ctx.results:
        if not res["success"]:
            for row in res["failed_rows"]:
                print(row)

This is also how you add your own reporting or storage. For example, a post-processor that uploads failing rows to your storage provider and sets res["csv_url"], so write_back_to_dscribe picks it up as failed_rows_url:

def upload_failed_rows(ctx):
    for res in ctx.results:
        if not res["success"] and res["failed_rows"]:
            res["csv_url"] = my_storage.upload_csv(res["rule_id"], res["failed_rows"])

Add both to postprocessors, before write_back_to_dscribe:

ctx = dq.run_validation(
    source_configs={...},
    postprocessors=[
        log_failed_rows,
        upload_failed_rows,
        dq.write_back_to_dscribe(),
    ],
)

Post-processors run in the order they are listed, so write_back_to_dscribe must come last to see csv_url (or ctx.report_url) once an earlier post-processor sets it.

Options

DScribeDQ.__init__

Parameter Type Default Description
api_key str — dScribe API key (or set DSCRIBE_API_KEY env var)
base_url str — dScribe API base URL (or set DSCRIBE_BASE_URL)
asset_id str — Asset UUID to validate (or set DSCRIBE_ASSET_ID)
log_level str INFO DEBUG, INFO, RESULT, WARNING, ERROR

DScribeDQ.run_validation

Parameter Type Default Description
source_configs dict {} Per-source connection settings keyed by server ID from ODCS spec
connector_config dict {} Default connection settings used when no per-source config found
collect_failed_rows bool True Fetch the actual failing rows for each failed rule
max_failed_rows int 1000 Max failing rows to fetch per rule. See Known limitations — does not apply to every rule type.
enable_profiling bool False Compute descriptive statistics (row count, null counts, etc.)
postprocessors list [] Pipeline steps to run after validation in order
audience str None Restrict to this audience's contract (or set DSCRIBE_CONTRACT_AUDIENCE). Defaults to the unlabeled "Default" contract if one exists, else whichever audience has the highest version.
contract_version str None Restrict to this exact contract version (or set DSCRIBE_CONTRACT_VERSION). Defaults to the latest version.

Known limitations

  • max_failed_rows does not apply to all rule types. It is respected for all built-in library rules (nullValues, missingValues, duplicateValues — including compound/multi-column rules — and invalidValues when defined using allowed or excluded values) and for SQL rules. It is not respected for regex-based invalidValues rules (expect_column_values_to_match_regex and expect_column_values_to_not_match_regex) or for expectations defined using a custom Great Expectations YAML block — for those, the number of returned failing rows is controlled by Great Expectations and capped at 200 regardless of max_failed_rows. This limit comes from Great Expectations' internal MAX_RESULT_RECORDS setting and cannot be configured by dscribe-dq.

Supported ODCS metrics

ODCS metric What it checks
rowCount Row count within expected bounds
nullValues No NULL values in a column
missingValues No missing/empty values in a column
duplicateValues All values in a column (or column set) are unique
invalidValues Values match an allowed list or regex pattern

Environment variable reference

Variable Description
DSCRIBE_API_KEY dScribe API key
DSCRIBE_ASSET_ID Asset UUID to validate
DSCRIBE_BASE_URL dScribe API base URL
DSCRIBE_CONTRACT_AUDIENCE Audience to restrict validation to (e.g. "sales", "finance")
DSCRIBE_CONTRACT_VERSION Contract version to restrict validation to
DATABRICKS_HOST Databricks workspace hostname
DATABRICKS_CLIENT_ID Azure AD service principal client ID
DATABRICKS_CLIENT_SECRET Azure AD service principal client secret
DATABRICKS_TENANT_ID Azure AD tenant ID
DATABRICKS_HTTP_PATH SQL warehouse HTTP path
DATABRICKS_WAREHOUSE_ID SQL warehouse ID (alternative to HTTP path)
DATABRICKS_CATALOG Default Unity Catalog catalog name
DATABRICKS_SCHEMA Default schema name
MSSQL_HOST MSSQL server hostname
MSSQL_DATABASE MSSQL database name
MSSQL_USER SQL Server username
MSSQL_PASSWORD SQL Server password
MSSQL_AUTH SQL Server or Entra ID
MSSQL_TENANT_ID Azure tenant ID (Entra ID auth only)
MSSQL_CLIENT_ID Azure client ID (Entra ID auth only)
MSSQL_CLIENT_SECRET Azure client secret (Entra ID auth only)
HANA_HOST SAP HANA / Data Warehouse Cloud hostname
HANA_PORT SQL port — 443 for SAP Data Warehouse Cloud, tenant SQL port (e.g. 3<instance>15) on-prem
HANA_DATABASE Tenant database name (on-prem MDC routing; not needed for DWC)
HANA_SCHEMA Schema containing the target table
HANA_TABLE Table name to validate
HANA_USER HANA username
HANA_PASSWORD HANA password
HANA_ENCRYPT true or false (default true)
HANA_VALIDATE_CERT true or false (default true)

Metadata

Release files for dscribe-dq 1.1.3

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

Source distribution (sdist)

Source distribution for dscribe-dq 1.1.3
File Size Uploaded
dscribe_dq-1.1.3.tar.gz 34.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dscribe-dq 1.1.3
File Interpreter ABI Platform
dscribe_dq-1.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 70.6 kB

Release files / dscribe_dq-1.1.3.tar.gz

Download URL dscribe_dq-1.1.3.tar.gz
Size 34.8 kB
Tags Source
SHA-256 checksum
How to use checksums
877ee344a1dfefe381fcffba421b99a32ad9bec63e12c592500446016222aea6
BLAKE2b-256 checksum
How to use checksums
84132359b520fe353cdf2e90b8ae8c37509d545b96ddecd0d8aab62e79d4c966
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.6.1 CPython/3.11.14 Darwin/24.6.0

Release files / dscribe_dq-1.1.3-py3-none-any.whl

Download URL dscribe_dq-1.1.3-py3-none-any.whl
Size 35.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f3a88284c5790de37ac5f925276c432f17242493fa55c9f37b3e20170082f047
BLAKE2b-256 checksum
How to use checksums
838f0607be7dd071cdcb60c29fbaa8005aabf6e8a3a2fa0e46116e29f0acbd98
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.6.1 CPython/3.11.14 Darwin/24.6.0

Release history Release notifications | RSS feed

1.1.4

2 release files

This release

1.1.3 This release

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.8

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

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