Tables
kelp.tables
¶
Generic model metadata API for use in any Spark job.
MaterializationConfig
module-attribute
¶
MaterializationConfig = Annotated[
AppendConfig
| OverwriteConfig
| MergeConfig
| Scd2Config,
Field(discriminator="mode"),
]
AppendConfig
pydantic-model
¶
Bases: _BaseMaterialization
Append the DataFrame to the target table.
Show JSON schema:
{
"additionalProperties": false,
"description": "Append the DataFrame to the target table.",
"properties": {
"options": {
"additionalProperties": {
"type": "string"
},
"description": "Extra Delta writer/merge options (e.g. {'mergeSchema': 'true'}).",
"title": "Options",
"type": "object"
},
"allow_full_refresh": {
"default": true,
"description": "Whether a caller-requested full refresh may drop and rebuild the target. Set to False to protect critical tables; the refresh is then skipped with a warning.",
"title": "Allow Full Refresh",
"type": "boolean"
},
"mode": {
"const": "append",
"default": "append",
"title": "Mode",
"type": "string"
}
},
"title": "AppendConfig",
"type": "object"
}
Fields:
-
options(dict[str, str]) -
allow_full_refresh(bool) -
mode(Literal['append'])
allow_full_refresh
pydantic-field
¶
Whether a caller-requested full refresh may drop and rebuild the target. Set to False to protect critical tables; the refresh is then skipped with a warning.
ColumnSelector
pydantic-model
¶
Bases: BaseModel
Include/exclude selector for a set of columns.
Exactly one of include or exclude may be set. Matching is
case-insensitive.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
include
|
Only these columns are selected. |
required | |
exclude
|
All columns except these are selected. |
required |
Show JSON schema:
{
"description": "Include/exclude selector for a set of columns.\n\nExactly one of ``include`` or ``exclude`` may be set. Matching is\ncase-insensitive.\n\nArgs:\n include: Only these columns are selected.\n exclude: All columns except these are selected.",
"properties": {
"include": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "Only these columns are selected (case-insensitive).",
"title": "Include"
},
"exclude": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "All columns except these are selected (case-insensitive).",
"title": "Exclude"
}
},
"title": "ColumnSelector",
"type": "object"
}
Fields:
Validators:
-
_validate_exclusive
apply
¶
Select from candidates, preserving their order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
candidates
|
list[str]
|
Columns to select from. |
required |
required
|
list[str] | None
|
Columns always kept, even when not selected. |
None
|
Returns:
| Type | Description |
|---|---|
list[str]
|
Selected column names in |
Source code in src/kelp/models/model_mat_config.py
MaterializationOptions
pydantic-model
¶
Bases: BaseModel
Switches for the steps kelp runs around a materialization write.
These are operational choices, not part of a model's write semantics, so they
live outside the mode config: project-wide defaults come from
kelp_project.yml, and a call site may override individual switches.
Show JSON schema:
{
"additionalProperties": false,
"description": "Switches for the steps kelp runs around a materialization write.\n\nThese are operational choices, not part of a model's write semantics, so they\nlive outside the mode config: project-wide defaults come from\n``kelp_project.yml``, and a call site may override individual switches.",
"properties": {
"apply_quality_checks": {
"default": true,
"description": "Whether DQX checks declared in model metadata are applied.",
"title": "Apply Quality Checks",
"type": "boolean"
},
"sync_metadata": {
"default": true,
"description": "Whether catalog metadata is synced afterwards. Requires a model.",
"title": "Sync Metadata",
"type": "boolean"
},
"apply_optimize": {
"default": true,
"description": "Whether OPTIMIZE runs after the write.",
"title": "Apply Optimize",
"type": "boolean"
},
"apply_vacuum": {
"default": true,
"description": "Whether VACUUM runs after the write.",
"title": "Apply Vacuum",
"type": "boolean"
},
"vacuum_lite": {
"default": true,
"description": "Whether VACUUM uses LITE mode. Only used when apply_vacuum is set.",
"title": "Vacuum Lite",
"type": "boolean"
}
},
"title": "MaterializationOptions",
"type": "object"
}
Config:
extra:forbid
Fields:
-
apply_quality_checks(bool) -
sync_metadata(bool) -
apply_optimize(bool) -
apply_vacuum(bool) -
vacuum_lite(bool)
apply_quality_checks
pydantic-field
¶
Whether DQX checks declared in model metadata are applied.
sync_metadata
pydantic-field
¶
Whether catalog metadata is synced afterwards. Requires a model.
vacuum_lite
pydantic-field
¶
Whether VACUUM uses LITE mode. Only used when apply_vacuum is set.
merged_with
¶
Return these options with the explicitly set fields of override applied.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
override
|
MaterializationOptions | dict | None
|
Options or mapping overriding individual switches, or |
required |
Returns:
| Type | Description |
|---|---|
MaterializationOptions
|
The effective options. Unset fields keep this instance's values, so a |
MaterializationOptions
|
call site only has to state what it wants to change. |
Source code in src/kelp/models/model_mat_config.py
MaterializedContext
dataclass
¶
Execution context optionally injected into materialized functions.
Attributes:
| Name | Type | Description |
|---|---|---|
spark |
SparkSession
|
Active SparkSession. |
this |
str
|
Fully qualified target table name (or provided name when unresolved). |
target_exists |
bool
|
Whether the target table exists before materialization. |
full_refresh |
bool
|
Whether a full refresh was requested by the caller. |
is_incremental
¶
MergeConfig
pydantic-model
¶
Bases: _BaseMerge
Merge rows by key, keeping one current version per key (SCD type 1).
Show JSON schema:
{
"$defs": {
"ColumnSelector": {
"description": "Include/exclude selector for a set of columns.\n\nExactly one of ``include`` or ``exclude`` may be set. Matching is\ncase-insensitive.\n\nArgs:\n include: Only these columns are selected.\n exclude: All columns except these are selected.",
"properties": {
"include": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "Only these columns are selected (case-insensitive).",
"title": "Include"
},
"exclude": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "All columns except these are selected (case-insensitive).",
"title": "Exclude"
}
},
"title": "ColumnSelector",
"type": "object"
},
"SqlConditions": {
"description": "Raw SQL conditions for the merge clauses.\n\nEscape hatch for cases the declarative fields cannot express. Every entry is a\nboolean SQL expression guarding one merge clause and may reference the\n``source`` and ``target`` aliases \u2014 nothing else about the merge is settable here.\n\nArgs:\n when_matched: Replaces the derived \"row changed\" condition on updates.\n when_not_matched: Extra condition applied to inserts of unmatched source rows.\n when_not_matched_by_source: Extra condition applied to target rows missing\n from the source. Requires ``missing_in_source: delete``.",
"properties": {
"when_matched": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Replaces the derived 'row changed' condition on matched updates.",
"title": "When Matched"
},
"when_not_matched": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Extra condition applied when inserting unmatched source rows.",
"title": "When Not Matched"
},
"when_not_matched_by_source": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Extra condition applied to target rows missing from the source. Requires missing_in_source='delete'.",
"title": "When Not Matched By Source"
}
},
"title": "SqlConditions",
"type": "object"
}
},
"additionalProperties": false,
"description": "Merge rows by key, keeping one current version per key (SCD type 1).",
"properties": {
"options": {
"additionalProperties": {
"type": "string"
},
"description": "Extra Delta writer/merge options (e.g. {'mergeSchema': 'true'}).",
"title": "Options",
"type": "object"
},
"allow_full_refresh": {
"default": true,
"description": "Whether a caller-requested full refresh may drop and rebuild the target. Set to False to protect critical tables; the refresh is then skipped with a warning.",
"title": "Allow Full Refresh",
"type": "boolean"
},
"keys": {
"description": "Business key columns identifying a row. Required.",
"items": {
"type": "string"
},
"minItems": 1,
"title": "Keys",
"type": "array"
},
"sequence_by": {
"description": "Columns ordering source rows in time. Multiple columns are compared as a struct. Used to deduplicate the batch and to ignore out-of-order rows.",
"items": {
"type": "string"
},
"title": "Sequence By",
"type": "array"
},
"columns": {
"anyOf": [
{
"$ref": "#/$defs/ColumnSelector"
},
{
"type": "null"
}
],
"default": null,
"description": "Which source columns reach the target. Keys are always included."
},
"track_changes": {
"anyOf": [
{
"$ref": "#/$defs/ColumnSelector"
},
{
"type": "null"
}
],
"default": null,
"description": "Which columns are compared to decide whether a row changed at all. When none of them differ, nothing is written: no update (merge) and no new version (scd2). Defaults to every written column except the keys."
},
"when_deleted": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "SQL predicate marking source rows as deletes (CDC tombstones).",
"title": "When Deleted"
},
"where": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Predicate narrowing the target rows taken into account.",
"title": "Where"
},
"ignore_null_updates": {
"default": false,
"description": "Whether a NULL source value leaves the stored value alone instead of replacing it, so partial CDC rows keep the previous value.",
"title": "Ignore Null Updates",
"type": "boolean"
},
"ignore_null_updates_columns": {
"anyOf": [
{
"$ref": "#/$defs/ColumnSelector"
},
{
"type": "null"
}
],
"default": null,
"description": "Which columns ignore_null_updates applies to. Defaults to every written column except the keys."
},
"schema_evolution": {
"default": true,
"description": "Whether new source columns are added to the target during the merge.",
"title": "Schema Evolution",
"type": "boolean"
},
"mode": {
"const": "merge",
"default": "merge",
"title": "Mode",
"type": "string"
},
"sql_conditions": {
"anyOf": [
{
"$ref": "#/$defs/SqlConditions"
},
{
"type": "null"
}
],
"default": null,
"description": "Raw SQL conditions for the merge clauses."
},
"insert_only_columns": {
"description": "Columns written on insert but left out of the update, so their first value survives (e.g. created_at). Unlike track_changes, which decides whether an update happens at all, this decides which columns an update may touch.",
"items": {
"type": "string"
},
"title": "Insert Only Columns",
"type": "array"
},
"missing_in_source": {
"default": "ignore",
"description": "What to do with target rows that the source does not contain.",
"enum": [
"ignore",
"delete"
],
"title": "Missing In Source",
"type": "string"
}
},
"required": [
"keys"
],
"title": "MergeConfig",
"type": "object"
}
Fields:
-
options(dict[str, str]) -
allow_full_refresh(bool) -
keys(list[str]) -
sequence_by(list[str]) -
columns(ColumnSelector | None) -
track_changes(ColumnSelector | None) -
when_deleted(str | None) -
where(str | None) -
ignore_null_updates(bool) -
ignore_null_updates_columns(ColumnSelector | None) -
schema_evolution(bool) -
mode(Literal['merge']) -
sql_conditions(SqlConditions | None) -
insert_only_columns(list[str]) -
missing_in_source(Literal['ignore', 'delete'])
allow_full_refresh
pydantic-field
¶
Whether a caller-requested full refresh may drop and rebuild the target. Set to False to protect critical tables; the refresh is then skipped with a warning.
sequence_by
pydantic-field
¶
Columns ordering source rows in time. Multiple columns are compared as a struct. Used to deduplicate the batch and to ignore out-of-order rows.
columns
pydantic-field
¶
Which source columns reach the target. Keys are always included.
track_changes
pydantic-field
¶
Which columns are compared to decide whether a row changed at all. When none of them differ, nothing is written: no update (merge) and no new version (scd2). Defaults to every written column except the keys.
when_deleted
pydantic-field
¶
SQL predicate marking source rows as deletes (CDC tombstones).
ignore_null_updates
pydantic-field
¶
Whether a NULL source value leaves the stored value alone instead of replacing it, so partial CDC rows keep the previous value.
ignore_null_updates_columns
pydantic-field
¶
Which columns ignore_null_updates applies to. Defaults to every written column except the keys.
schema_evolution
pydantic-field
¶
Whether new source columns are added to the target during the merge.
insert_only_columns
pydantic-field
¶
Columns written on insert but left out of the update, so their first value survives (e.g. created_at). Unlike track_changes, which decides whether an update happens at all, this decides which columns an update may touch.
missing_in_source
pydantic-field
¶
What to do with target rows that the source does not contain.
ignore_null_columns
¶
Return the columns whose NULL source values must not replace stored values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
candidates
|
list[str]
|
Columns eligible for the rule, normally the written columns except the keys. |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
Selected column names, empty when |
Source code in src/kelp/models/model_mat_config.py
ModelRegistry
¶
Registered materialized models and their dependency graph.
Create an empty registry.
Source code in src/kelp/tables/materialization/runner.py
register
¶
Register a model, logging a warning when it replaces an existing name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spec
|
ModelSpec
|
Model specification to register. |
required |
Source code in src/kelp/tables/materialization/runner.py
get
¶
Return the spec registered under name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Model name. |
required |
Returns:
| Type | Description |
|---|---|
ModelSpec
|
The registered model specification. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If no model is registered under |
Source code in src/kelp/tables/materialization/runner.py
names
¶
clear
¶
toposort
¶
Dependency-ordered model names; all of them when names is None.
Transitive dependencies of the requested models are always included.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
names
|
list[str] | None
|
Models to order, or None for every registered model. |
None
|
Returns:
| Type | Description |
|---|---|
list[str]
|
Model names ordered so that every dependency precedes its consumers. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If a requested model or one of its dependencies is unknown. |
ValueError
|
If the dependency graph contains a cycle. |
Source code in src/kelp/tables/materialization/runner.py
levels
¶
Dependency levels: every model in a level may run concurrently.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
names
|
list[str] | None
|
Models to group, or None for every registered model. |
None
|
Returns:
| Type | Description |
|---|---|
list[list[str]]
|
Lists of model names, each level depending only on earlier levels. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If a requested model or one of its dependencies is unknown. |
ValueError
|
If the dependency graph contains a cycle. |
Source code in src/kelp/tables/materialization/runner.py
ModelSpec
dataclass
¶
A registered materialized model.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Unique model name. |
fn |
Callable[..., Any]
|
Callable executing the materialization, invoked with |
depends_on |
list[str]
|
Names of models that must run before this one. |
OverwriteConfig
pydantic-model
¶
Bases: _BaseMaterialization
Replace the target table contents with the DataFrame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
replace_where
|
Optional predicate limiting the overwrite to matching rows
(Delta |
required |
Show JSON schema:
{
"additionalProperties": false,
"description": "Replace the target table contents with the DataFrame.\n\nArgs:\n replace_where: Optional predicate limiting the overwrite to matching rows\n (Delta ``replaceWhere``) instead of the whole table.",
"properties": {
"options": {
"additionalProperties": {
"type": "string"
},
"description": "Extra Delta writer/merge options (e.g. {'mergeSchema': 'true'}).",
"title": "Options",
"type": "object"
},
"allow_full_refresh": {
"default": true,
"description": "Whether a caller-requested full refresh may drop and rebuild the target. Set to False to protect critical tables; the refresh is then skipped with a warning.",
"title": "Allow Full Refresh",
"type": "boolean"
},
"mode": {
"const": "overwrite",
"default": "overwrite",
"title": "Mode",
"type": "string"
},
"replace_where": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Predicate limiting the overwrite to matching rows (Delta replaceWhere).",
"title": "Replace Where"
}
},
"title": "OverwriteConfig",
"type": "object"
}
Fields:
-
options(dict[str, str]) -
allow_full_refresh(bool) -
mode(Literal['overwrite']) -
replace_where(str | None)
Runner
¶
Executes registered materialized models in dependency order.
Create a runner.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
registry
|
ModelRegistry | None
|
Registry to run models from; defaults to the module-level
|
None
|
spark
|
SparkSession | None
|
SparkSession handed to every model. Defaults to the session active when a run starts. |
None
|
Source code in src/kelp/tables/materialization/runner.py
plan_one
¶
Dependency-ordered names needed to build name, including name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Model to plan. |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
Model names in the order they must run. |
Source code in src/kelp/tables/materialization/runner.py
plan_all
¶
run_one
¶
Run exactly this one model and return its result.
Upstreams are NOT run - use run(plan_one(name)) for that.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Model to run. |
required |
full_refresh
|
bool
|
Whether to rebuild the target from scratch. |
False
|
Returns:
| Type | Description |
|---|---|
Any
|
Whatever the model function returns. |
Source code in src/kelp/tables/materialization/runner.py
run
¶
Run models in dependency order, optionally running each level concurrently.
With parallel=True the models of a dependency level are submitted from
several threads to the same SparkSession, which Spark supports. The session
is resolved once here and handed to each model, since worker threads cannot
see the active session themselves.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
names
|
list[str] | None
|
Models to run, or None for every registered model. |
None
|
full_refresh
|
bool
|
Whether to rebuild the targets from scratch. |
False
|
parallel
|
bool
|
Whether to run independent models of a level concurrently. |
False
|
max_workers
|
int
|
Maximum number of threads used when |
4
|
Source code in src/kelp/tables/materialization/runner.py
run_all
¶
Run every registered model in dependency order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
full_refresh
|
bool
|
Whether to rebuild the targets from scratch. |
False
|
parallel
|
bool
|
Whether to run independent models of a level concurrently. |
False
|
max_workers
|
int
|
Maximum number of threads used when |
4
|
Source code in src/kelp/tables/materialization/runner.py
Scd2Columns
pydantic-model
¶
Bases: BaseModel
Names of the history-tracking columns maintained by mode: scd2.
Defaults match Databricks AUTO CDC (apply_changes) so SCD2 tables stay
interchangeable between SDP pipelines and kelp Spark jobs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
valid_from
|
Column holding the sequence value a version becomes valid at. |
required | |
valid_to
|
Column holding the sequence value a version is superseded at. |
required | |
is_current
|
Optional boolean column maintained alongside |
required | |
open_value
|
SQL expression |
required |
Show JSON schema:
{
"description": "Names of the history-tracking columns maintained by ``mode: scd2``.\n\nDefaults match Databricks AUTO CDC (``apply_changes``) so SCD2 tables stay\ninterchangeable between SDP pipelines and kelp Spark jobs.\n\nArgs:\n valid_from: Column holding the sequence value a version becomes valid at.\n valid_to: Column holding the sequence value a version is superseded at.\n is_current: Optional boolean column maintained alongside ``valid_to``.\n open_value: SQL expression ``valid_to`` takes while a version is current,\n instead of ``NULL`` \u2014 e.g. ``\"'2999-12-31'\"`` or ``\"9999999999\"``.",
"properties": {
"valid_from": {
"default": "__START_AT",
"description": "Column holding the sequence value a version becomes valid at.",
"title": "Valid From",
"type": "string"
},
"valid_to": {
"default": "__END_AT",
"description": "Column holding the sequence value a version is superseded at (NULL for the current version unless open_value is set).",
"title": "Valid To",
"type": "string"
},
"is_current": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional boolean column maintained alongside valid_to.",
"title": "Is Current"
},
"open_value": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "SQL expression valid_to takes while a version is current, instead of NULL (e.g. \"'2999-12-31'\"). Must be castable to the sequence_by type.",
"title": "Open Value"
}
},
"title": "Scd2Columns",
"type": "object"
}
Fields:
-
valid_from(str) -
valid_to(str) -
is_current(str | None) -
open_value(str | None)
valid_from
pydantic-field
¶
Column holding the sequence value a version becomes valid at.
valid_to
pydantic-field
¶
Column holding the sequence value a version is superseded at (NULL for the current version unless open_value is set).
is_current
pydantic-field
¶
Optional boolean column maintained alongside valid_to.
open_value
pydantic-field
¶
SQL expression valid_to takes while a version is current, instead of NULL (e.g. "'2999-12-31'"). Must be castable to the sequence_by type.
all_names
¶
Return every history column name that is configured.
Scd2Config
pydantic-model
¶
Bases: _BaseMerge
Track full row history by key, closing superseded versions (SCD type 2).
Show JSON schema:
{
"$defs": {
"ColumnSelector": {
"description": "Include/exclude selector for a set of columns.\n\nExactly one of ``include`` or ``exclude`` may be set. Matching is\ncase-insensitive.\n\nArgs:\n include: Only these columns are selected.\n exclude: All columns except these are selected.",
"properties": {
"include": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "Only these columns are selected (case-insensitive).",
"title": "Include"
},
"exclude": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "All columns except these are selected (case-insensitive).",
"title": "Exclude"
}
},
"title": "ColumnSelector",
"type": "object"
},
"Scd2Columns": {
"description": "Names of the history-tracking columns maintained by ``mode: scd2``.\n\nDefaults match Databricks AUTO CDC (``apply_changes``) so SCD2 tables stay\ninterchangeable between SDP pipelines and kelp Spark jobs.\n\nArgs:\n valid_from: Column holding the sequence value a version becomes valid at.\n valid_to: Column holding the sequence value a version is superseded at.\n is_current: Optional boolean column maintained alongside ``valid_to``.\n open_value: SQL expression ``valid_to`` takes while a version is current,\n instead of ``NULL`` \u2014 e.g. ``\"'2999-12-31'\"`` or ``\"9999999999\"``.",
"properties": {
"valid_from": {
"default": "__START_AT",
"description": "Column holding the sequence value a version becomes valid at.",
"title": "Valid From",
"type": "string"
},
"valid_to": {
"default": "__END_AT",
"description": "Column holding the sequence value a version is superseded at (NULL for the current version unless open_value is set).",
"title": "Valid To",
"type": "string"
},
"is_current": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional boolean column maintained alongside valid_to.",
"title": "Is Current"
},
"open_value": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "SQL expression valid_to takes while a version is current, instead of NULL (e.g. \"'2999-12-31'\"). Must be castable to the sequence_by type.",
"title": "Open Value"
}
},
"title": "Scd2Columns",
"type": "object"
}
},
"additionalProperties": false,
"description": "Track full row history by key, closing superseded versions (SCD type 2).",
"properties": {
"options": {
"additionalProperties": {
"type": "string"
},
"description": "Extra Delta writer/merge options (e.g. {'mergeSchema': 'true'}).",
"title": "Options",
"type": "object"
},
"allow_full_refresh": {
"default": true,
"description": "Whether a caller-requested full refresh may drop and rebuild the target. Set to False to protect critical tables; the refresh is then skipped with a warning.",
"title": "Allow Full Refresh",
"type": "boolean"
},
"keys": {
"description": "Business key columns identifying a row. Required.",
"items": {
"type": "string"
},
"minItems": 1,
"title": "Keys",
"type": "array"
},
"sequence_by": {
"description": "Columns ordering source rows in time. Required for scd2: they become the valid_from/valid_to interval bounds.",
"items": {
"type": "string"
},
"minItems": 1,
"title": "Sequence By",
"type": "array"
},
"columns": {
"anyOf": [
{
"$ref": "#/$defs/ColumnSelector"
},
{
"type": "null"
}
],
"default": null,
"description": "Which source columns reach the target. Keys are always included."
},
"track_changes": {
"anyOf": [
{
"$ref": "#/$defs/ColumnSelector"
},
{
"type": "null"
}
],
"default": null,
"description": "Which columns are compared to decide whether a row changed at all. When none of them differ, nothing is written: no update (merge) and no new version (scd2). Defaults to every written column except the keys."
},
"when_deleted": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "SQL predicate marking source rows as deletes (CDC tombstones).",
"title": "When Deleted"
},
"where": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Predicate narrowing the target rows taken into account.",
"title": "Where"
},
"ignore_null_updates": {
"default": false,
"description": "Whether a NULL source value leaves the stored value alone instead of replacing it, so partial CDC rows keep the previous value.",
"title": "Ignore Null Updates",
"type": "boolean"
},
"ignore_null_updates_columns": {
"anyOf": [
{
"$ref": "#/$defs/ColumnSelector"
},
{
"type": "null"
}
],
"default": null,
"description": "Which columns ignore_null_updates applies to. Defaults to every written column except the keys."
},
"schema_evolution": {
"default": true,
"description": "Whether new source columns are added to the target during the merge.",
"title": "Schema Evolution",
"type": "boolean"
},
"mode": {
"const": "scd2",
"default": "scd2",
"title": "Mode",
"type": "string"
},
"history": {
"$ref": "#/$defs/Scd2Columns",
"description": "Names of the history-tracking columns kelp maintains."
}
},
"required": [
"keys",
"sequence_by"
],
"title": "Scd2Config",
"type": "object"
}
Fields:
-
options(dict[str, str]) -
allow_full_refresh(bool) -
keys(list[str]) -
columns(ColumnSelector | None) -
track_changes(ColumnSelector | None) -
when_deleted(str | None) -
where(str | None) -
ignore_null_updates(bool) -
ignore_null_updates_columns(ColumnSelector | None) -
schema_evolution(bool) -
mode(Literal['scd2']) -
sequence_by(list[str]) -
history(Scd2Columns)
allow_full_refresh
pydantic-field
¶
Whether a caller-requested full refresh may drop and rebuild the target. Set to False to protect critical tables; the refresh is then skipped with a warning.
columns
pydantic-field
¶
Which source columns reach the target. Keys are always included.
track_changes
pydantic-field
¶
Which columns are compared to decide whether a row changed at all. When none of them differ, nothing is written: no update (merge) and no new version (scd2). Defaults to every written column except the keys.
when_deleted
pydantic-field
¶
SQL predicate marking source rows as deletes (CDC tombstones).
ignore_null_updates
pydantic-field
¶
Whether a NULL source value leaves the stored value alone instead of replacing it, so partial CDC rows keep the previous value.
ignore_null_updates_columns
pydantic-field
¶
Which columns ignore_null_updates applies to. Defaults to every written column except the keys.
schema_evolution
pydantic-field
¶
Whether new source columns are added to the target during the merge.
sequence_by
pydantic-field
¶
Columns ordering source rows in time. Required for scd2: they become the valid_from/valid_to interval bounds.
ignore_null_columns
¶
Return the columns whose NULL source values must not replace stored values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
candidates
|
list[str]
|
Columns eligible for the rule, normally the written columns except the keys. |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
Selected column names, empty when |
Source code in src/kelp/models/model_mat_config.py
SqlConditions
pydantic-model
¶
Bases: BaseModel
Raw SQL conditions for the merge clauses.
Escape hatch for cases the declarative fields cannot express. Every entry is a
boolean SQL expression guarding one merge clause and may reference the
source and target aliases — nothing else about the merge is settable here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
when_matched
|
Replaces the derived "row changed" condition on updates. |
required | |
when_not_matched
|
Extra condition applied to inserts of unmatched source rows. |
required | |
when_not_matched_by_source
|
Extra condition applied to target rows missing
from the source. Requires |
required |
Show JSON schema:
{
"description": "Raw SQL conditions for the merge clauses.\n\nEscape hatch for cases the declarative fields cannot express. Every entry is a\nboolean SQL expression guarding one merge clause and may reference the\n``source`` and ``target`` aliases \u2014 nothing else about the merge is settable here.\n\nArgs:\n when_matched: Replaces the derived \"row changed\" condition on updates.\n when_not_matched: Extra condition applied to inserts of unmatched source rows.\n when_not_matched_by_source: Extra condition applied to target rows missing\n from the source. Requires ``missing_in_source: delete``.",
"properties": {
"when_matched": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Replaces the derived 'row changed' condition on matched updates.",
"title": "When Matched"
},
"when_not_matched": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Extra condition applied when inserting unmatched source rows.",
"title": "When Not Matched"
},
"when_not_matched_by_source": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Extra condition applied to target rows missing from the source. Requires missing_in_source='delete'.",
"title": "When Not Matched By Source"
}
},
"title": "SqlConditions",
"type": "object"
}
Fields:
-
when_matched(str | None) -
when_not_matched(str | None) -
when_not_matched_by_source(str | None)
when_matched
pydantic-field
¶
Replaces the derived 'row changed' condition on matched updates.
when_not_matched
pydantic-field
¶
Extra condition applied when inserting unmatched source rows.
when_not_matched_by_source
pydantic-field
¶
Extra condition applied to target rows missing from the source. Requires missing_in_source='delete'.
init
¶
init(
project_file_path=None,
target=None,
init_vars=None,
manifest_file_path=None,
refresh=False,
store_in_global=True,
run_policy_checks=False,
log_level=None,
)
Initialize kelp runtime context from current directory.
When manifest_file_path is provided (or resolved from KELP_MANIFEST_FILE
environment variable), the context is loaded directly from a pre-built
manifest JSON file, skipping all project discovery, Jinja rendering, and
metadata loading.
When policy_config.enabled is True in the project settings, metadata
governance policies are evaluated immediately after loading. Warn-severity
violations are logged; error-severity violations raise a RuntimeError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_file_path
|
str | None
|
Path to project file or directory. |
None
|
target
|
str | None
|
Target environment name. |
None
|
init_vars
|
dict[str, Any] | None
|
Runtime variable overrides. |
None
|
manifest_file_path
|
str | None
|
Path to a manifest JSON file. When provided, skips source file loading. Also resolved from KELP_MANIFEST_FILE env var. |
None
|
refresh
|
bool
|
If True, recreate context even if one already exists. |
False
|
store_in_global
|
bool
|
Whether to store context globally. |
True
|
run_policy_checks
|
bool
|
Whether to run policy checks. |
False
|
log_level
|
str | None
|
Optional log level to configure. |
None
|
Returns:
| Type | Description |
|---|---|
MetaRuntimeContext
|
The initialized MetaRuntimeContext. |
Source code in src/kelp/config/config.py
columns
¶
ddl
¶
func
¶
Get the fully qualified name for a Unity Catalog function.
get_model
¶
ref
¶
schema
¶
Get the Spark schema DDL for a model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Model name. |
required |
exclude
|
list[str] | None
|
Column names to exclude from the schema. |
None
|
Returns:
| Type | Description |
|---|---|
str | None
|
Spark schema DDL string, or |
Source code in src/kelp/tables/api.py
schema_lite
¶
Get the raw Spark schema without constraints or generated columns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Model name. |
required |
exclude
|
list[str] | None
|
Column names to exclude from the schema. |
None
|
Returns:
| Type | Description |
|---|---|
str | None
|
Spark schema DDL string, or |
Source code in src/kelp/tables/api.py
source
¶
source_options
¶
materialize
¶
materialize(
*,
dataframe,
name,
config=None,
options=None,
full_refresh=False,
full_refresh_strategy="drop",
spark=None,
)
Materialize a DataFrame to Delta Lake according to a materialization config.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataframe
|
DataFrame
|
DataFrame to materialize. |
required |
name
|
str
|
Unqualified kelp model name, or a qualified table name to write without metadata. |
required |
config
|
MaterializationConfig | dict | None
|
Materialization config or mapping. Replaces the model's config entirely when both are present. |
None
|
options
|
MaterializationOptions | dict | None
|
Overrides for the steps run around the write — quality checks,
catalog sync, OPTIMIZE and VACUUM. Unset switches fall back to the
project's |
None
|
full_refresh
|
bool
|
Whether to rebuild the target from scratch first. Ignored with
a warning when the config sets |
False
|
full_refresh_strategy
|
FullRefreshStrategy
|
How a full refresh resets the target — |
'drop'
|
spark
|
SparkSession | None
|
SparkSession to use. Defaults to the active session. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
The DataFrame that was written, which is the input frame minus any rows |
DataFrame
|
quality checks dropped. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no SparkSession is available. |
LookupError
|
If |
ValueError
|
If quality checks found errors and the model's
|
Source code in src/kelp/tables/materialization/orchestrator.py
materialized
¶
materialized(
*,
name: str | None = None,
config: MaterializationConfig | dict | None = None,
options: MaterializationOptions | dict | None = None,
depends_on: list[str] | None = None,
full_refresh: bool = False,
full_refresh_strategy: FullRefreshStrategy = "drop",
) -> Callable[
[Callable[..., DataFrame]], Callable[..., DataFrame]
]
materialized(
func=None,
*,
name=None,
config=None,
options=None,
depends_on=None,
full_refresh=False,
full_refresh_strategy="drop",
)
Decorator that materializes the returned DataFrame.
Usable bare (@materialized) or called (@materialized(name=...)).
Model matching uses name when provided; otherwise the wrapped function
name is used. An unqualified name must match a kelp model; pass a qualified
table name to materialize without metadata.
The wrapper accepts full_refresh and spark keywords at call time, which
override the decorator's value and the active session and are not passed on to
the wrapped function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Callable[..., DataFrame] | None
|
The decorated function when used bare. |
None
|
name
|
str | None
|
Optional kelp model name, or a qualified table name. |
None
|
config
|
MaterializationConfig | dict | None
|
Optional materialization config, replacing the model's config. |
None
|
options
|
MaterializationOptions | dict | None
|
Overrides for the steps run around the write — quality checks,
catalog sync, OPTIMIZE and VACUUM. Unset switches fall back to the
project's |
None
|
depends_on
|
list[str] | None
|
Model names this model must run after, for the runner. |
None
|
full_refresh
|
bool
|
Whether to rebuild the target from scratch before writing. |
False
|
full_refresh_strategy
|
FullRefreshStrategy
|
How a full refresh resets the target — |
'drop'
|
Returns:
| Type | Description |
|---|---|
Callable[..., DataFrame] | Callable[[Callable[..., DataFrame]], Callable[..., DataFrame]]
|
The decorated callable, or the decorator when called with options. |
Source code in src/kelp/tables/materialization/decorator.py
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | |
kelp.service.model_manager.KelpModel
dataclass
¶
KelpModel(
name,
table_type=None,
comment=None,
table_properties=None,
spark_conf=None,
path=None,
partition_cols=None,
cluster_by_auto=None,
cluster_by=None,
row_filter=None,
auto_ttl=None,
fqn=None,
schema=None,
schema_lite=None,
dqx_quality=None,
validation_table=None,
quarantine_table=None,
target_table=None,
root_model=None,
materialization=None,
meta=None,
)
build_ddl
¶
Build a CREATE TABLE DDL statement directly from this model's properties.
Unlike :meth:get_ddl, this does not require root_model — it uses
schema, fqn, table_type, table_properties,
cluster_by, partition_cols, path, and comment
directly from the dataclass fields.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
if_not_exists
|
bool
|
Emit |
True
|
or_replace
|
bool
|
Emit |
False
|
Returns:
| Type | Description |
|---|---|
str | None
|
DDL string, or |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/kelp/service/model_manager.py
get_ddl
¶
Source code in src/kelp/service/model_manager.py
get_replace_ddl
¶
Build a CREATE OR REPLACE TABLE statement for this model.
Used by the replace full-refresh strategy: unlike DROP + CREATE,
replacing keeps the table's identity, so Unity Catalog grants, tags and
history survive the refresh.
Returns:
| Type | Description |
|---|---|
str | None
|
DDL string, or |
Source code in src/kelp/service/model_manager.py
kelp.service.model_manager.KelpSdpModel
dataclass
¶
KelpSdpModel(
name,
table_type=None,
comment=None,
table_properties=None,
spark_conf=None,
path=None,
partition_cols=None,
cluster_by_auto=None,
cluster_by=None,
row_filter=None,
auto_ttl=None,
fqn=None,
schema=None,
schema_lite=None,
dqx_quality=None,
validation_table=None,
quarantine_table=None,
target_table=None,
root_model=None,
materialization=None,
meta=None,
expect_all=None,
expect_all_or_fail=None,
expect_all_or_drop=None,
expect_all_or_quarantine=None,
)
Bases: KelpModel
params
¶
Source code in src/kelp/service/model_manager.py
params_raw
¶
params_cst
¶
Source code in src/kelp/service/model_manager.py
get_sdp_params
¶
Source code in src/kelp/service/model_manager.py
get_ddl
¶
Source code in src/kelp/service/model_manager.py
build_ddl
¶
Build a CREATE TABLE DDL statement directly from this model's properties.
Unlike :meth:get_ddl, this does not require root_model — it uses
schema, fqn, table_type, table_properties,
cluster_by, partition_cols, path, and comment
directly from the dataclass fields.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
if_not_exists
|
bool
|
Emit |
True
|
or_replace
|
bool
|
Emit |
False
|
Returns:
| Type | Description |
|---|---|
str | None
|
DDL string, or |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/kelp/service/model_manager.py
get_replace_ddl
¶
Build a CREATE OR REPLACE TABLE statement for this model.
Used by the replace full-refresh strategy: unlike DROP + CREATE,
replacing keeps the table's identity, so Unity Catalog grants, tags and
history survive the refresh.
Returns:
| Type | Description |
|---|---|
str | None
|
DDL string, or |