Skip to main content

Lakehouse-Aligned YAML Kit for Engineering Rules

Project description

🐟 Layker 🐟
Lakehouse‑Aligned YAML Kit for Engineering Rules

Declarative table metadata control for Databricks & Spark.
Layker turns a YAML spec into safe, validated DDL with a built‑in audit log.
If nothing needs to change, Layker exits cleanly. If something must change, you’ll see it first.


What is Layker?

Layker is a Python package for managing table DDL, metadata, and auditing with a single YAML file as the source of truth.

Highlights

  • Declarative – author schemas, tags, constraints, and properties in YAML.
  • Diff‑first – Layker computes a diff against the live table; “no diff” = no work.
  • Safe evolution – add/rename/drop column intents are detected and gated by required Delta properties.
  • Auditable – every applied change is logged with before/after snapshots and a concise differences dictionary.
  • Serverless‑friendly – gracefully skips REFRESH TABLE on serverless (prints a warning).

Installation

Stable:

pip install layker

Latest (main):

pip install "git+https://github.com/Levi-Gagne/layker.git"

Python 3.8+ and Spark 3.3+ are recommended.


Quickstart

1) Author a YAML spec

Minimal example (save as src/layker/resources/example.yaml):

catalog: dq_dev
schema: lmg_sandbox
table: layker_test

columns:
  1:
    name: id
    datatype: bigint
    nullable: false
    active: true
  2:
    name: name
    datatype: string
    nullable: true
    active: true

table_comment: Demo table managed by Layker
table_properties:
  delta.columnMapping.mode: "name"
  delta.minReaderVersion: "2"
  delta.minWriterVersion: "5"

primary_key: [id]
tags:
  domain: demo
  owner: team-data

2) Sync from Python

from pyspark.sql import SparkSession
from layker.main import run_table_load

spark = SparkSession.builder.appName("layker").getOrCreate()

run_table_load(
    yaml_path="src/layker/resources/example.yaml",
    env="prd",
    dry_run=False,
    mode="all",                 # validate | diff | apply | all
    audit_log_table=True        # True=default audit YAML, False=disable, or str path to an audit YAML
)

3) Or via CLI

python -m layker src/layker/resources/example.yaml prd false all true

When audit_log_table=True, Layker uses the packaged default: layker/resources/layker_audit.yaml.
You can also pass a custom YAML path. Either way, the YAML defines the audit table’s location.


How it works (at a glance)

  1. Validate YAML → fast fail with exact reasons, or proceed.
  2. Snapshot live table (if it exists).
  3. Compute differences between YAML snapshot and table snapshot.
    • If no changes (i.e., the diff contains only full_table_name), exit with a success message and no audit row is written.
  4. Validate differences (schema‑evolution preflight):
    • Detects add/rename/drop column intents.
    • Requires Delta properties for evolution:
      • delta.columnMapping.mode = name
      • delta.minReaderVersion = 2
      • delta.minWriterVersion = 5
    • On missing requirements, prints details and exits.
  5. Apply changes (create/alter) using generated SQL.
  6. Audit (only if changes were applied and auditing is enabled):
    • Writes a row containing:
      • before_value (JSON), differences (JSON), after_value (JSON)
      • change_category (create or update)
      • change_key (human‑readable sequence per table, see below)
      • env, yaml_path, fqn, timestamps, actor, etc.

Audit log model

The default audit YAML (layker/resources/layker_audit.yaml) defines these columns (in order):

  • change_id – UUID per row
  • run_id – optional job/run identifier
  • env – environment/catalog prefix
  • yaml_path – the source YAML path that initiated the change
  • fqn – fully qualified table name
  • change_categorycreate or update (based on whether a “before” snapshot was present)
  • change_key – readable sequence per table:
    • First ever create: create-1
    • Subsequent updates on that lineage: create-1~update-1, create-1~update-2, …
    • If the table is later dropped & re‑created: the next lineage becomes create-2, etc.
  • before_value – JSON snapshot before change (may be null on first create)
  • differences – JSON diff dict that was applied
  • after_value – JSON snapshot after change
  • notes – optional free text
  • created_at / created_by / updated_at / updated_by

Uniqueness expectation: (fqn, change_key) is effectively unique over time.


Modes & parameters

  • mode: validate | diff | apply | all
    • validate: only YAML validation (exits on success)
    • diff: prints proposed changes and exits
    • apply: applies changes only
    • all: validate → diff → apply → audit
  • audit_log_table:
    • False – disable auditing
    • True – use default layker/resources/layker_audit.yaml
    • str – path to a custom audit YAML (the YAML governs the destination table)
  • No‑op safety: if there are no changes, Layker exits early and skips audit.

Notes on serverless

Databricks serverless does not support REFRESH TABLE.
Layker detects this and prints a warning; the rest of the flow continues.


Repository layout (typical)

src/
  layker/
    __init__.py
    __main__.py
    main.py
    differences.py
    loader.py
    logger.py
    snapshot_yaml.py
    snapshot_table.py
    resources/
      layker_audit.yaml
    utils/
      color.py
      printer.py
      spark.py
      timer.py
      paths.py
      table.py
    validators/
      params.py
      differences.py

Troubleshooting

  • Spark Connect / serverless: Layker avoids schema inference issues by using explicit schemas when writing the audit row.
  • Single quotes in comments: Layker sanitizes YAML comments to avoid SQL quoting errors.
  • No changes but I still see output: A diff containing only full_table_name means no change; Layker exits early with a success message and writes no audit row.

Contributing & License

PRs and issues welcome.
License: see LICENSE in the repo.

Built for engineers, by engineers.
🐟 LAYKER 🐟

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

layker-0.1.0.tar.gz (53.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

layker-0.1.0-py3-none-any.whl (55.0 kB view details)

Uploaded Python 3

File details

Details for the file layker-0.1.0.tar.gz.

File metadata

  • Download URL: layker-0.1.0.tar.gz
  • Upload date:
  • Size: 53.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for layker-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ec78695fe93a07839a114248831c13afd3d6352534ab1eaa9e21b661b7bb1159
MD5 f63122319cab1a638100bf85baca21b2
BLAKE2b-256 34ef0862893e9f94d5ca5599a179edf17c357a9e44e87d6b9681602293526490

See more details on using hashes here.

Provenance

The following attestation bundles were made for layker-0.1.0.tar.gz:

Publisher: workflow.yaml on Levi-Gagne/layker

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file layker-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: layker-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 55.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for layker-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 eadf8a512a2b0a670ca9c7deb7cc9b694ad7425f79204083cb1b48457bb49237
MD5 5409385e3c9fab335a94016d8b83ca84
BLAKE2b-256 eee3113f8757d2f648c28f63b9e25d6ddedbbf93303a1c9f77f2379797662b86

See more details on using hashes here.

Provenance

The following attestation bundles were made for layker-0.1.0-py3-none-any.whl:

Publisher: workflow.yaml on Levi-Gagne/layker

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page