Skip to main content

A lightweight, immutable struct library with type enforcement.

Project description

# pystructlight

**A lightweight, memory‑efficient, and type‑safe immutable data structure for Python.**

`pystructlight` lets you define schemas for your data objects and ensures that every instance adheres to those types at runtime – all while keeping a tiny memory footprint thanks to `__slots__`.

## Features

- **Immutable** – instances cannot be modified after creation
- **Runtime type enforcement** – validates that all field values match your schema
- **Memory efficient** – uses `__slots__` to avoid per‑instance `__dict__`
- **Flexible field definitions** – support for default values, custom validators, and type coercion
- **Rich type support**`Union`, `Optional`, `Literal`, `Any`, generic containers (`list[T]`, `dict[K, V]`, etc.)
- **Convenient methods**`evolve()`, `matches()`, `to_dict()`, `from_dict()`, `is_instance()`
- **Positional or keyword instantiation** – choose the style you prefer

## Installation

```bash
pip install pystructlight

Quick Start

1. Define a Struct

Pass a name and a dictionary mapping field names to their expected types (or to a FieldDef for advanced options).

from pystructlight import Struct, field

# Simple type‑only schema
Book = Struct("Book", {
    "title": str,
    "author": str,
    "pages": int,
    "is_hardcover": bool,
})

# Schema with defaults, validator, and coercion
Person = Struct("Person", {
    "name": str,
    "age": field(int, default=0, validator=lambda x: x >= 0),
    "email": str,
    "tags": field(list[str], default=list),
})

2. Create Instances

Use keyword arguments…

book1 = Book.new(
    title="The Great Gatsby",
    author="F. Scott Fitzgerald",
    pages=180,
    is_hardcover=False
)

…or positional arguments (in the order the fields were defined):

book2 = Book.new("1984", "George Orwell", 328, True)

3. Access and Use

print(book1.title)                     # "The Great Gatsby"
print(book1.pages)                     # 180

# Immutability
try:
    book1.pages = 200
except AttributeError:
    print("Cannot modify immutable struct!")

# Runtime type checking
try:
    Book.new("The Hobbit", "J.R.R. Tolkien", "many", True)
except TypeError as e:
    print(e)   # Field 'pages': expected int, got str

# Convert to dict
data = book1.to_dict()
# {'title': 'The Great Gatsby', 'author': 'F. Scott Fitzgerald', 'pages': 180, 'is_hardcover': False}

# Create from dict
book3 = Book.from_dict({"title": "Moby Dick", "author": "Herman Melville", "pages": 585, "is_hardcover": False})

Advanced Field Definitions

Use the field() helper to add defaults, validators, or type coercion.

Parameter Description
type Expected type (e.g. str, int, list[str], Union[int, str], Any)
default Default value. Can be a constant or a callable (e.g. list, dict).
validator Callable that receives the value and returns True, a string error, or False.
coerce If True, attempts to convert the input to the expected type (e.g. int("42")).
from pystructlight import Struct, field

Config = Struct("Config", {
    "timeout": field(float, default=5.0, coerce=True),
    "retries": field(int, default=3, validator=lambda x: 0 <= x <= 10),
    "tags": field(list[str], default=list),
})

c = Config.new(timeout="2.5", retries=5, tags=["prod", "api"])
print(c.timeout)   # 2.5 (coerced from string)
print(c.retries)   # 5
print(c.tags)      # ['prod', 'api']

Methods on Struct Instances

Every instance provides the following methods:

Method Description
to_dict() Returns a dict mapping field names to values.
evolve(**changes) Returns a new instance with updated fields (original unchanged).
matches(**kwargs) Returns True if all given fields equal the specified values.
__iter__() Iterates over field values (in definition order).
__len__() Number of fields.
__repr__() Human‑readable representation.
book = Book.new(title="Brave New World", author="Aldous Huxley", pages=268, is_hardcover=False)

# Evolve
new_book = book.evolve(pages=300, is_hardcover=True)
print(new_book.pages)      # 300
print(book.pages)          # 268 (unchanged)

# Matching
if book.matches(title="Brave New World"):
    print("It's the same book!")

# Iteration
for value in book:
    print(value)

Methods on the Struct Type

The object returned by Struct() (a StructType) provides:

Method Description
new(*args, **kwargs) Creates a new instance.
from_dict(data: dict) Creates an instance from a dictionary (calls new(**data)).
is_instance(obj) Returns True if obj is an instance of this exact struct type.
Book.is_instance(book)   # True
Book.is_instance("foo")  # False

Runtime Type Checking

pystructlight validates values against your schema when you create the instance.

Supported types include:

  • Built‑in types: int, float, str, bool, bytes, None
  • Type unions: Union[int, str], int | str (Python 3.10+)
  • Optional[T] (same as Union[T, None])
  • Literal["red", "green"]
  • Any (no checking)
  • Generic containers: list[T], tuple[T], set[T], frozenset[T], dict[K, V]
  • Any user‑defined class

Example:

from typing import Union, Literal, Any

Data = Struct("Data", {
    "id": Union[int, str],
    "status": Literal["active", "inactive"],
    "payload": Any,
})

d = Data.new(id=42, status="active", payload={"anything": 123})  # OK
d2 = Data.new(id="abc", status="inactive", payload=None)         # OK

# This fails:
# Data.new(id=3.14, status="active", payload=None)   # id must be int or str

Memory Efficiency

Instances do not have a __dict__. All fields are stored in a compact tuple, and access is routed through __slots__. The overhead is roughly the same as a namedtuple, but with full runtime type checking.

import sys

Book = Struct("Book", {"title": str, "pages": int})
b = Book.new("The Pearl", 96)
print(sys.getsizeof(b))   # typically 56 bytes (plus the tuple, but overall very small)

API Reference

Struct(name: str, schema: dict) -> StructType

Creates a new struct type.

  • name – the name of the struct (used in repr and error messages)
  • schema – dictionary where each key is a field name and each value is either a type or a FieldDef (created by field()).

field(type, default=_MISSING, validator=None, coerce=False) -> FieldDef

Returns a field definition for use in a schema.

  • type – the expected type (e.g. str, list[int]).
  • default – optional default value (if callable, it is called each time a default is needed).
  • validator – optional callable (value) -> bool | str | None. Return False or a string to raise an error.
  • coerce – if True, tries to convert the input to the given type using typ(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

pystructlight-0.1.2.tar.gz (13.6 kB view details)

Uploaded Source

Built Distribution

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

pystructlight-0.1.2-py3-none-any.whl (11.4 kB view details)

Uploaded Python 3

File details

Details for the file pystructlight-0.1.2.tar.gz.

File metadata

  • Download URL: pystructlight-0.1.2.tar.gz
  • Upload date:
  • Size: 13.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pystructlight-0.1.2.tar.gz
Algorithm Hash digest
SHA256 a833a5f77169c4d96bd2209a6ff3cedbb826972e9a6d11bda4a1ddddc4b11819
MD5 f8fb073883f1b148cc591663e4dc1206
BLAKE2b-256 57e1457aa991baa2c2580db976f13496f0b12427b0099e000c158304f8d5753c

See more details on using hashes here.

File details

Details for the file pystructlight-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: pystructlight-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 11.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pystructlight-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 80244da3a3f81db98c7017affa5d48e78e5adbbd19b04ea8a1420d9ff02f1142
MD5 c706ca02e639c7f24ed21677f6d45f73
BLAKE2b-256 ed12ea7de57b30a1216b44421a5a86907eebc639123e9dae2f43e19323164545

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