Skip to main content

Policy-driven guardrails for common data transformations

Project description

Custos

Custos is a lightweight, policy-driven helper library for applying explicit, auditable guardrails to common data transformations at ingestion time.

Custos helps data engineers make routine transformations—such as JSON flattening, schema normalization, PII handling, and row-level quality checks—consistent, visible, and safe, without replacing existing tools or platforms.

Custos is Latin for “guardian.”

Design choice: explicit over inferred

Custos does not attempt to infer schemas, repair data, or guess intent. All transformations are explicitly declared in policy. If a value is changed, dropped, or rejected, it is recorded and reported.

Why Custos exists

In many data pipelines, the same transformation logic is repeatedly rewritten:

  • flattening nested JSON

  • renaming columns

  • casting types

  • masking or dropping PII

  • filtering invalid rows

These transformations are often:

  • implicit

  • scattered across scripts

  • hard to audit

  • easy to change accidentally

Custos makes these decisions explicit by defining them once, as policy, and applying them consistently.

What Custos is (and is not)

✅ Custos is

  • A helper library, not a platform

  • Policy-driven and explicit

  • Designed for ingestion-time transformations

  • Focused on correctness and auditability

  • Easy to add — and easy to remove

❌ Custos is not

  • A replacement for dbt, Spark, or SQL

  • A data modeling tool

  • An orchestration framework

  • An auto-fixing or inference engine

  • A governance or compliance platform

Custos deliberately avoids “magic.” If data is changed, dropped, or rejected, it is logged and reported.

Core features

  • Controlled JSON flattening (with depth and array handling)

  • Column renaming and schema normalization

  • Type casting with explicit failure modes

  • PII masking, hashing, or dropping

  • Row-level data quality enforcement

  • Structured audit reports for every run

Design principles

  • Explicit over clever

  • Fail loudly or drop safely — never guess

  • Policy as code

  • Guardrails, not inference

  • Low friction for developers

Custos is designed to complement existing pipelines, not redefine them.

Quick example

from custos import PolicyTransformer

transformer = PolicyTransformer(
    policy="policy.yml",
    mode="strict"  # strict | dry_run
)

df_out, report = transformer.apply(df_in)

A single policy file controls what happens. A structured report explains exactly what changed and why.

When to use Custos

  • In ingestion or staging pipelines

  • When transforming semi-structured data

  • When enforcing basic correctness early

  • When you want repeatable, auditable transformations

When not to use Custos

  • For warehouse modeling (use dbt)

  • For cross-table validation

  • For complex business logic

  • For inference-based data repair

Status

Custos is currently early-stage and intentionally small. Its feature set is deliberately constrained to remain predictable and auditable.

Installation

pip install custos

Example: ingestion guardrails in action

Input data (what you receive)

import pandas as pd

df_in = pd.DataFrame({
    "Order ID": ["101", "102", "x"],
    "Total Price": ["10.5", "oops", "30.25"],
    "email": ["john@test.com", "bad-email", None],
    "payload": [
        {"user": {"name": "Ann", "roles": ["admin"]}},
        {"user": {"name": "Bob"}},
        None,
    ],
})

This data has:

  • mixed types

  • invalid values

  • PII

  • nested JSON

  • rows that should not pass ingestion

Policy (what you declare once)

version: 1

json_flatten:
  rules:
    - column: payload
      prefix: payload
      max_depth: 2
      arrays: stringify
      drop_source: true

schema:
  rename:
    "Order ID": "order_id"
    "Total Price": "total_price"

  types:
    order_id: int
    total_price: float

  cast:
    on_cast_fail: set_null

pii:
  rules:
    - column: email
      action: mask
      mask_style: email

quality:
  default_on_fail: drop_row
  rules:
    - name: total_price_non_negative
      column: total_price
      not_null: true
      min: 0

    - name: order_id_required
      column: order_id
      not_null: true

This policy explicitly states:

  • how JSON should be flattened

  • how columns should be renamed

  • how types should be enforced

  • how PII should be handled

  • which rows are allowed to pass

Apply the policy

from custos import PolicyTransformer

transformer = PolicyTransformer(
    policy="policy.yml",
    mode="strict"
)

df_out, report = transformer.apply(df_in)

Output data (what continues downstream)

   payload.user.name payload.user.roles  total_price  order_id          email
0                Ann           ["admin"]         10.5       101  j***@test.com

What happened:

  • JSON was flattened

  • invalid casts became null

  • PII was masked

  • rows failing quality checks were dropped

  • only clean, explicit, auditable data passed through

Audit report (what Custos records)

rename_applied
cast_failures
pii_masked
quality_violations
rows_dropped_due_to_quality

Each step includes structured details:

  • which columns were affected

  • how many rows failed

  • why rows were dropped

Nothing is implicit. Nothing is hidden.

Why this matters

Without Custos, this logic is usually:

  • scattered across scripts

  • partially undocumented

  • easy to change accidentally

  • difficult to audit later

With Custos:

  • the transformation intent is explicit

  • the behavior is repeatable

  • the outcome is explainable

That’s the core value.

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

custos_guardrails-0.1.0.tar.gz (20.6 kB view details)

Uploaded Source

Built Distribution

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

custos_guardrails-0.1.0-py3-none-any.whl (19.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: custos_guardrails-0.1.0.tar.gz
  • Upload date:
  • Size: 20.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.4

File hashes

Hashes for custos_guardrails-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f8b51c2cb30e3d8d43ac4c7195c5675f9943da7b0c5b78931ea9a58bef68c0c3
MD5 e68061f4dfd563560c40af1dd9439d62
BLAKE2b-256 4c2b9963b47c4072f69ab84de7db908c9c17a39020ea9d5f7f94d9729f0f9625

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for custos_guardrails-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2daeaa6a708b8e32a1cde6841629f52108c73592a2a02ba9687c5e352c95b385
MD5 0287db69ee0322dccd0d446c9e1b9096
BLAKE2b-256 8f7f920bd8edb3fbf6d7b9733c771aabc5f06ac2907e792593b10dd523ea1c45

See more details on using hashes here.

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