Skip to main content

LabSchema

CI PyPI version Python Versions License: MIT

LabSchema is a Python library that turns messy lab-style tables (CSV, TSV) into typed schemas with physical units and validation.

Features

  • Declarative schemas — Define column names, types, units, and constraints once
  • Physical units — Parse units from headers and convert values automatically via Pint
  • Comprehensive validation — Get detailed error reports with row, column, and error codes
  • Schema inference — Generate draft schemas from your data files
  • Multiple exports — Export schemas as JSON or JSON Schema (draft 2020-12)
  • CLI included — Validate files, infer schemas, and export from the command line

Installation

pip install labschema

For pandas DataFrame support:

pip install "labschema[pandas]"

Quick Start

30-Second Example

from labschema import TableSchema, Field, u
from labschema.io import read_csv

# Define your schema
schema = TableSchema(
    name="plate_reader_run",
    primary_key=("well",),
    fields=[
        Field("well", str, pattern=r"^[A-H](?:[1-9]|1[0-2])$"),
        Field("absorbance", float, unit=u.dimensionless, ge=0),
        Field("temperature", float, unit=u.degC, ge=-273.15),
    ],
)

# Validate your data
result = read_csv("run_042.csv", schema=schema)

if not result.ok:
    result.report.print_summary()
else:
    df = result.to_pandas()  # Requires labschema[pandas]
    print(f"Loaded {len(df)} valid rows")

Sample Output

run_042.csv: 96 rows, 93 valid, 4 errors, 1 warning

  type_error (2)
    line 14, column "absorbance": value "OVRFLW" is not a valid float
    line 51, column "absorbance": value "n.d." is not a valid float
  less_than_minimum (1)
    line 22, column "temperature (°C)": value -300 is less than minimum -273.15 °C
  duplicate_primary_key (1)
    line 88: well "H12" already appears on line 97
  extra_column (warning) (1)
    column "Notes" does not match any field

CLI Usage

Validate a file

labschema validate data.csv --schema schema.json

Infer a schema from data

labschema infer data.csv --name my_schema -o schema.json

Export to JSON Schema

labschema export-schema schema.json --format jsonschema -o schema.jsonschema

Options

labschema validate --help
labschema infer --help
labschema export-schema --help

Schema Definition

Fields

from labschema import Field, u

# Basic string field
Field("name", str)

# Numeric with unit and bounds
Field("temperature", float, unit=u.degC, ge=-273.15)

# Nullable field
Field("notes", str, nullable=True)

# Field with enum constraint
Field("status", str, enum=["active", "inactive", "pending"])

# Field with regex pattern
Field("well", str, pattern=r"^[A-H][1-9]|1[0-2]$")

# Field with default value
Field("replicate", int, default=1)

# Field with custom validator
def positive(value):
    if value <= 0:
        raise ValueError("Must be positive")
    return value

Field("count", int, validators=[positive])

TableSchema

from labschema import TableSchema, Field, u

schema = TableSchema(
    name="experiment_data",
    version="1.0",
    description="Data from plate reader experiments",
    primary_key=("sample_id", "replicate"),
    extra_columns="warn",  # "ignore", "warn", or "error"
    fields=[
        Field("sample_id", str),
        Field("replicate", int, ge=1),
        Field("absorbance", float, unit=u.dimensionless, ge=0),
        Field("concentration", float, unit="mg/L", nullable=True),
    ],
    metadata={
        "instrument": "Synergy H1",
        "protocol": "Standard absorbance",
    },
)

Units

LabSchema uses Pint for unit handling. Units can be specified in:

  • Field definitions: Field("temp", float, unit=u.degC)
  • Column headers: temperature (°C), concentration [mg/L]

Supported Aliases

Input Resolves to
°C, degC degree_Celsius
µL, μL, uL microliter
% percent
a.u., AU, RFU, OD dimensionless
rpm revolutions_per_minute
M mol/L

Unit Conversion

Values are automatically converted from header units to field units:

# Field declares liters
Field("volume", float, unit="L")

# CSV header has milliliters
# volume [mL]
# 1000

# Result: volume = 1.0 (converted to liters)

Validation

Error Codes

Code Description
missing_column Schema field has no matching header
extra_column Header matches no field
duplicate_column Multiple headers map to one field
unit_incompatible Header unit incompatible with field unit
row_length_mismatch Wrong number of cells in row
null_not_allowed Missing value in non-nullable field
type_error Value cannot be coerced to dtype
less_than_minimum Violates ge/gt constraint
greater_than_maximum Violates le/lt constraint
not_in_enum Value not in enum
pattern_mismatch String doesn't match pattern
duplicate_primary_key Primary key already seen

Accessing Results

result = read_csv("data.csv", schema=schema)

# Check if valid
if result.ok:
    print("All data is valid!")

# Get valid records
records = result.to_records()

# Get as DataFrame (requires pandas)
df = result.to_pandas()

# Inspect errors
for error in result.errors:
    print(f"{error.code}: {error.message}")

# Get detailed report
result.report.print_summary()

# JSON output
print(result.report.to_json())

Schema Inference

from labschema import infer_schema

# Infer from file
schema = infer_schema("data.csv", sample_rows=100, name="my_data")

# Save as JSON
schema.save("schema.json")

# Or get as Python code for editing
from labschema.infer import schema_to_python
print(schema_to_python(schema))

Export Formats

LabSchema JSON (round-trippable)

# Save
schema.save("schema.json")

# Load
schema = TableSchema.load("schema.json")

JSON Schema (draft 2020-12)

json_schema = schema.to_json_schema()

Reader Options

result = read_csv(
    "data.csv",
    schema=schema,
    delimiter=";",           # Auto-detected if not specified
    decimal=",",             # European decimal separator
    thousands=" ",           # Thousands separator to strip
    encoding="utf-8-sig",    # Handles BOM
    skip_rows=2,             # Skip preamble lines
    comment="#",             # Ignore comment lines
    na_values=["NA", "-"],   # Custom missing values
    max_errors=100,          # Stop after N errors
)

Development

# Clone the repository
git clone https://github.com/labschema/labschema.git
cd labschema

# Install development dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run linting
ruff check src/ tests/
ruff format --check src/ tests/

# Type checking
mypy --strict src/

Contributing

See CONTRIBUTING.md for guidelines.

License

MIT License. See LICENSE for details.

Metadata

Release files for labschema 0.1.0

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

Source distribution (sdist)

Source distribution for labschema 0.1.0
File Size Uploaded Provenance
labschema-0.1.0.tar.gz 36.0 kB With provenance Details

Built distribution (wheel)

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

Total release size: 66.3 kB

Release files / labschema-0.1.0.tar.gz

Download URL labschema-0.1.0.tar.gz
Size 36.0 kB
Tags Source
SHA-256 checksum
How to use checksums
7d195405d8fe392bce389b174406769ebd4a44e656e2ee853185c4d9737c0e73
BLAKE2b-256 checksum
How to use checksums
d27d2e12c22d83b3ec18d6a35d51a4778ab8bdf438b7d39a5a9201019b2219a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / labschema-0.1.0-py3-none-any.whl

Download URL labschema-0.1.0-py3-none-any.whl
Size 30.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2a6ee244b56d29a5e312e645e52d5c17e7f13e89b8dc3dd7cae7f3388c73cfd6
BLAKE2b-256 checksum
How to use checksums
32c53c57aa5a0828a7e2dcb7106f81038728425e840065215f068df7b8a5f83c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Security for labschema 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for labschema-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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