Skip to main content

Polypolars

CI PyPI Python 3.8+ License: MIT Code style: ruff

Generate type-safe Polars DataFrames effortlessly using polyfactory

Inspired by polyspark, polypolars lets you create realistic test DataFrames from your Python data models—with automatic schema inference for Polars.

Docs: See the docs/ folder and run mkdocs serve for the full API reference and examples.

Example

from dataclasses import dataclass
from polypolars import polars_factory

@polars_factory
@dataclass
class User:
    id: int
    name: str
    email: str

# Generate 1000 rows instantly:
df = User.build_dataframe(size=1000)
print(df.head())

Example output (data varies per run):

shape: (5, 3)
┌──────┬──────────────────────┬──────────────────────┐
│ id   ┆ name                 ┆ email                │
│ ---  ┆ ---                  ┆ ---                  │
│ i64  ┆ str                  ┆ str                  │
╞══════╪══════════════════════╪══════════════════════╡
│ 3167 ┆ QmYHeLMDMxWChjihAFxU ┆ vHGMKHjXsMBlxLuhqpUE │
│ 1028 ┆ hvLXPtlqURtwzqeyJruo ┆ ePDAdtelIEiRfEuAgoPz │
│ 9048 ┆ NhnyGGQsTjxPEndxaOCt ┆ znmByWtpwofUGKolkJrs │
│  971 ┆ ZlkxcjcVAZfLUkCwHRFG ┆ PTtzmMHcvLQPcOrAgFpl │
│ 3813 ┆ tIqqrgyYjULzdyRKkMKK ┆ tMAFeQewaQFtRGEvOdqW │
└──────┴──────────────────────┴──────────────────────┘

Contents

Why Polypolars?

  • Factory pattern: Leverage polyfactory for data generation
  • Type-safe schema: Python types become Polars dtypes automatically
  • Nullable handling: Optional[T] and defaults are reflected in the schema
  • Complex types: Nested structs, lists, and dicts (as list-of-structs)
  • Multiple models: Dataclasses, Pydantic, and TypedDict

Installation

pip install polypolars

For development:

pip install "polypolars[dev]"

Quick Start

from dataclasses import dataclass
from typing import Optional
from polypolars import polars_factory

@polars_factory
@dataclass
class Product:
    product_id: int
    name: str
    price: float
    description: Optional[str] = None
    in_stock: bool = True

# Build Polars DataFrame
df = Product.build_dataframe(size=100)
print(df.head())

# Or get dicts
dicts = Product.build_dicts(size=50)

Example output (first 5 rows; data varies per run):

shape: (5, 5)
┌────────────┬──────────────────────┬──────────────┬──────────────────────┬──────────┐
│ product_id ┆ name                 ┆ price        ┆ description          ┆ in_stock │
│ ---        ┆ ---                  ┆ ---          ┆ ---                  ┆ ---      │
│ i64        ┆ str                  ┆ f64          ┆ str                  ┆ bool     │
╞════════════╪══════════════════════╪══════════════╪══════════════════════╪══════════╡
│ 5582       ┆ hKJsoOOXlwgLIiiWOCJP ┆ 2.2760e8     ┆ rTUACBLlGBlHXIjzVvPt ┆ false    │
│ 7099       ┆ ZgUiDVJirxAYRrWIPnpS ┆ 274887.17671 ┆ bHGMXNFRLSDifpywMZrY ┆ true     │
│ 5372       ┆ MTtVHJkqneaCkoyZNgio ┆ 1.5195e7     ┆ HsAmRwgaphvQxOCJwjSr ┆ false    │
│ 8650       ┆ fTBYFPiWMFCKauieEXlu ┆ -7.8765e8    ┆ UAnyfVhTUmvcjtzbCufq ┆ true     │
│ 1023       ┆ MCtTOwvJTjfbpPELcFKm ┆ -97.933431   ┆ PMEHaEOGaoJiDaomXdVX ┆ false    │
└────────────┴──────────────────────┴──────────────┴──────────────────────┴──────────┘

Classic factory class

from polypolars import PolarsFactory

class ProductFactory(PolarsFactory[Product]):
    __model__ = Product

df = ProductFactory.build_dataframe(size=100)

Convenience function

from polypolars import build_polars_dataframe

df = build_polars_dataframe(Product, size=100)

Schema inference

Schema is inferred from your type hints, so all-null columns still get the correct type:

@polars_factory
@dataclass
class User:
    id: int
    email: Optional[str]  # nullable string in Polars

df = User.build_dataframe(size=100)  # schema: id Int64, email String

From dicts

dicts = Product.build_dicts(size=1000)
# Convert to DataFrame when needed:
df = Product.create_dataframe_from_dicts(dicts)

Pydantic

from pydantic import BaseModel, Field
from polypolars import polars_factory

@polars_factory
class User(BaseModel):
    id: int = Field(gt=0)
    username: str = Field(min_length=3, max_length=20)
    email: str
    is_active: bool = True

df = User.build_dataframe(size=500)

Type mapping

Python Polars
str String
int Int64
float Float64
bool Boolean
datetime Datetime
date Date
List[T] List(T)
Dict[K,V] List(Struct(key, value))
Optional[T] T (nullable)
Tuple[T, ...] List(T)
Tuple[T, T, ...] (fixed) Array(T, n)
Dataclass / Pydantic Struct(...)

Use schema_overrides (e.g. {"col": pl.Categorical}) to override inferred types.

LazyFrame and chunked building

# LazyFrame
lf = Product.build_lazy_dataframe(size=10_000)

# Chunked building for very large size (lower memory)
df = Product.build_dataframe(size=1_000_000, chunk_size=10_000)

CLI

# Export schema
polypolars schema export myapp.models:User --output schema.txt

# Validate a file against a model
polypolars schema validate myapp.models:User data.parquet

# Generate sample data
polypolars generate myapp.models:User --size 1000 --output users.parquet --format parquet

I/O and testing

from polypolars import (
    save_as_parquet,
    load_parquet,
    load_and_validate,
    infer_schema,
    assert_dataframe_equal,
    assert_schema_equal,
)

df = User.build_dataframe(size=1000)
save_as_parquet(df, "users.parquet")

# Load and validate
schema = infer_schema(User)
df2 = load_and_validate("users.parquet", expected_schema=schema)

assert_dataframe_equal(df, df2, check_order=False)

License

MIT

Metadata

Release files for polypolars 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for polypolars 0.1.1
File Size Uploaded
polypolars-0.1.1.tar.gz 5.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for polypolars 0.1.1
File Interpreter ABI Platform
polypolars-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 10.4 kB

Release files / polypolars-0.1.1.tar.gz

Download URL polypolars-0.1.1.tar.gz
Size 5.3 kB
Tags Source
SHA-256 checksum
How to use checksums
aefeacd71f503f426980379dac4e90153f6091dc37c1cf8c94cb63cc1da6f0a2
BLAKE2b-256 checksum
How to use checksums
f19ed0d9432d0c700b80eca0dc1283239496ecf614ec70826b2cf4f520f5d66d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.8.18

Release files / polypolars-0.1.1-py3-none-any.whl

Download URL polypolars-0.1.1-py3-none-any.whl
Size 5.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cd1ee593505dca1b672c8cbdbb5673b2f6e36d3dbe165e4b121ece661804a8de
BLAKE2b-256 checksum
How to use checksums
a785aa8a8d10e244b96f8fb3665afea450be1507a7cc938ad8da37ea28ef43d2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.8.18

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page