Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Nyctea logo

Nyctea

Polars-based data validation library with an extensible OOP validator architecture.

Features

Validator system

  • Extensible: create custom parsers and checks by inheriting from base classes
  • Type-safe: generic validator classes with runtime validation
  • Discoverable: tag-based validator discovery and registration

Customizable pipeline

  • Flexible: add, remove, or reorder validation phases
  • Validated: strict dependency enforcement prevents invalid configurations
  • Observable: built-in logging and metrics collection

Schema-centric API

  • Intuitive: schema.validate(df, registry), the schema owns validation
  • Pythonic: clean, object-oriented design
  • Out-of-core: built on Polars LazyFrame, designed for larger-than-RAM data

Installation

pip install nyctea
# or with uv
uv add nyctea

Quick start

import polars as pl
from nyctea import Registry, SchemaModel, register_builtins

# Define schema
schema = SchemaModel.from_dict({
    "columns": {
        "name": {
            "dtype": "Utf8",
            "parsers": [{"name": "strip"}, {"name": "lower"}],
            "nullable": False,
        },
        "age": {
            "dtype": "Int64",
            "parsers": [{"name": "to_int"}],
            "checks": [{"name": "min_value", "args": {"min": 0}}],
            "nullable": False,
        },
    }
})

# Register built-in validators
registry = Registry()
register_builtins(registry)

# Load and validate data
df = pl.scan_csv("data.csv")
result = schema.validate(df, registry)

# Inspect results
print(result.report.summary())
print(result.data.collect())

Creating custom validators

Custom parser (OOP)

import polars as pl
from nyctea.validators.base import ValidatorMetadata
from nyctea.validators.column import ColumnParser


class TrimParser(ColumnParser):
    def __init__(self):
        super().__init__(ValidatorMetadata(
            name="trim",
            description="Remove whitespace",
            tags=["string", "cleaning"],
        ))

    def execute(self, column: pl.Expr, **kwargs) -> pl.Expr:
        return column.str.strip_chars()

    def validate_args(self, **kwargs) -> None:
        pass  # No arguments


registry.register_column_parser(TrimParser())

Custom check (functional)

import polars as pl
from nyctea.validators.decorators import ValidatorDecorator

decorators = ValidatorDecorator(registry)


@decorators.column_check(name="positive", tags=["numeric"])
def is_positive(column: pl.Expr) -> pl.Expr:
    return column > 0

Architecture

Validator[TInput, TOutput]
├── ColumnValidator[pl.Expr, pl.Expr]
│   ├── ColumnParser (transformations)
│   └── ColumnCheck (validations)
└── FrameValidator[pl.LazyFrame, pl.LazyFrame]
    ├── FrameParser (transformations)
    └── FrameCheck (validations)

Registry
├── column_parsers: ValidatorRegistry[ColumnParser]
├── column_checks: ValidatorRegistry[ColumnCheck]
├── frame_parsers: ValidatorRegistry[FrameParser]
└── frame_checks: ValidatorRegistry[FrameCheck]

ValidationPipeline
├── ColumnResolutionPhase (synonyms)
├── ColumnParsingPhase (transformations)
├── CoercionPhase (dtype coercion)
└── ColumnCheckPhase (checks, nullable enforcement)

Testing

uv run pytest tests/ -v
uv run pytest tests/ --cov=src/nyctea --cov-report=term --cov-report=html
uv run ruff check src/ tests/
uv run ty check src/nyctea

CI runs linting, type checking, and the test suite on Python 3.11 through 3.14 for every pull request.

Documentation

Contributing

Contributions are welcome. Open an issue before starting anything beyond a trivial fix; see docs/development/contributing.md for the full workflow (issue-first, branch and PR conventions, CI overview) and DEVELOPMENT.md for local setup.

License

MIT

Download files

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

Source Distribution

nyctea-0.2.0b1.tar.gz (46.1 kB view details)

Uploaded Source

Built Distribution

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

nyctea-0.2.0b1-py3-none-any.whl (60.4 kB view details)

Uploaded Python 3

File details

Details for the file nyctea-0.2.0b1.tar.gz.

File metadata

  • Download URL: nyctea-0.2.0b1.tar.gz
  • Upload date:
  • Size: 46.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for nyctea-0.2.0b1.tar.gz
Algorithm Hash digest
SHA256 92201ab87e11a11d558966f26db7d53170c5e27851663a57798b00d6db2e1b48
MD5 fa58ebf7c52cd36403e361ab64ac71b7
BLAKE2b-256 d8b3df0c3e55b78a7e16f7e7c672a2a339f252b801f2fd07c0b537f0f11b4d5c

See more details on using hashes here.

Provenance

The following attestation bundles were made for nyctea-0.2.0b1.tar.gz:

Publisher: pypi-publish.yaml on yannick-vinkesteijn/nyctea

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

File details

Details for the file nyctea-0.2.0b1-py3-none-any.whl.

File metadata

  • Download URL: nyctea-0.2.0b1-py3-none-any.whl
  • Upload date:
  • Size: 60.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for nyctea-0.2.0b1-py3-none-any.whl
Algorithm Hash digest
SHA256 7a1157fa4635b6da650e89d0193077030fd5f3afa56d48012812f2774edcf3ca
MD5 24bbc2a65140145c9ce9f6691241410c
BLAKE2b-256 656a0b16909faf2281ab5b77b89caaea0df7aa35de37c2f8dd909d3b5fc4317d

See more details on using hashes here.

Provenance

The following attestation bundles were made for nyctea-0.2.0b1-py3-none-any.whl:

Publisher: pypi-publish.yaml on yannick-vinkesteijn/nyctea

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

Release history Release notifications | RSS feed

This release

0.2.0b1 This release

2 files

Supported by

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