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.3.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.3-py3-none-any.whl (11.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pystructlight-0.1.3.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.3.tar.gz
Algorithm Hash digest
SHA256 e1f112e61c172314b9fc244c51a34a6436e75321727783d6537d261f5249f3d5
MD5 d0a54329aedc241e1b342543f2619ced
BLAKE2b-256 597558f1965b68413bd559790ccc0151d03d75e3da02bd248033365af29bdc36

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pystructlight-0.1.3-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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 470faad1d922f22d09d672276f10ec493e9d56251315dcd6d08d40b6b62003d3
MD5 3f1010c706c2450c84a18992e369b913
BLAKE2b-256 4d2de4d5c37e5abbf69bdb592fcb8a2291c4c251ebacdc51799b1066369eaf37

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