Setup: every example on this page uses these imports
import dataframely as dy
import polars as pl
import dagster_dataframely as ddEvery rule has a severity, "error" or "warn", as a dbt test does. A rule is "error" unless the schema declares "warn".
| severity | a row that fails the rule | the rule’s check |
|---|---|---|
"error" |
is not written to the table: the run fails, or with filter=True the package writes the row under <name>__error_rows |
fails at ERROR |
"warn" |
is written to the table, unless it also fails an "error" rule |
fails at WARN |
Validation shows what each kind of run writes, and Filtering error rows shows the error rows.
The schema declares each severity, so every asset that uses the schema has the same severities:
class LenientOrdersSchema(dy.Schema):
order_id = dy.String(
primary_key=True,
regex=r"^ORD-\d{4}$",
metadata={"dagster_dataframely": {"severity": {"regex": "warn"}}},
)
amount = dy.Float64(nullable=False, min=0.0)
note = dy.String(
nullable=True,
max_length=100,
metadata={"dagster_dataframely": {"severity": "warn"}},
)
__dagster_dataframely__ = {"severity": {"amount_is_rounded": "warn"}}
@dy.rule()
def amount_is_rounded(cls) -> pl.Expr:
"""Require whole cents."""
return (cls.amount.col * 100).round() == cls.amount.col * 100A column rule’s severity goes in the column’s metadata, under the key dagster_dataframely. Its severity is one value for every rule on the column, as on note, or a mapping from rule name to value, as on order_id. Dataframely does not read metadata, so the key does not change how Dataframely validates.
A schema-level rule’s severity goes in the class attribute __dagster_dataframely__. A schema-level rule is primary_key or a @dy.rule(), and neither has a column to declare it on. The attribute takes the same two forms: one value for every schema-level rule, or a mapping.
A subclass has its parent’s declarations. The Columns tab does not show the dagster_dataframely key as a tag.
A severity mapping names Dataframely’s rule name: the part after the | in the check’s dataframely/rule metadata, such as regex in order_id|regex. Four column arguments generate a rule under a different name, and the package reads the argument as that rule:
| you can write | the rule it names |
|---|---|
nullable |
nullability |
allow_inf |
inf |
allow_nan |
nan |
check, when check= is a list or a dict |
every check__* rule on the column |
A dy.List or dy.Array adds inner_ to the rule names of its inner column, such as inner_nullability. A dy.Struct adds inner_<field>_ to the rule names of each field, such as inner_email_nullability. The arguments in the table do not name those rules, so dd.asset raises on inner_nullable.
dd.asset raises on a declaration it cannot readdd.asset checks the declarations when you declare the asset, and raises InvalidSeverityError on one it cannot read:
class MisspelledSchema(dy.Schema):
amount = dy.Float64(
min=0.0, metadata={"dagster_dataframely": {"severity": {"minimum": "warn"}}}
)
try:
dd.asset(MisspelledSchema)
except dd.errors.InvalidSeverityError as error:
print(error)The `dagster_dataframely` metadata of column 'amount' in MisspelledSchema names 'minimum', which is not a rule of column 'amount'. The rules of column 'amount' are 'nullability', 'min', 'inf', 'nan'.
It raises for these mistakes:
dagster_dataframely entry or a __dagster_dataframely__ that is not a mapping;severity under dagster_dataframely or in __dagster_dataframely__;"error", "warn" or a mapping of rule names to those, including dg.AssetCheckSeverity.WARN;__dagster_dataframely__ on a schema with no schema-level rules;amount|min, in __dagster_dataframely__;With filter=False, the default, a check whose rules include an "error" rule is blocking, like the column-schema check. With filter=True, no rule’s check is blocking.
The check specs of orders show which checks are blocking:
@dd.asset(LenientOrdersSchema)
def orders() -> pl.DataFrame:
return pl.DataFrame()
{spec.name: spec.blocking for spec in orders.check_specs}{'dy_schema__columns': True,
'dy_rule__amount_is_rounded': False,
'dy_rule__primary_key': True,
'dy_rule__order_id__nullability': True,
'dy_rule__order_id__regex': False,
'dy_rule__amount__nullability': True,
'dy_rule__amount__min': True,
'dy_rule__amount__inf': True,
'dy_rule__amount__nan': True,
'dy_rule__note__max_length': False}
The Checks tab marks each blocking check. Dagster does not execute the assets downstream in the same run when a blocking check fails at ERROR. A failing check also sets the asset’s health: “Degraded” for a check at ERROR, and “Warning” for a check at WARN.
With check_granularity="column", one check reports for all of a column’s rules (Settings):
filter=False and any of its rules is "error".ERROR when a failing rule is "error", and at WARN when only "warn" rules failed.So a collapsed check whose "warn" rule failed and whose "error" rule passed fails at WARN, and Dagster does not fail the step. Its metadata still lists the failures of each rule.