Skip to content

lzjever/serilux

Repository files navigation

Serilux 📦

PyPI version Python 3.7+ License Documentation CI codecov

Serilux is a powerful, flexible serialization framework for Python objects. With its intuitive API and automatic type registration, you can easily serialize and deserialize complex object hierarchies with minimal code.

✨ Why Serilux?

  • 🎯 Simple API: Just inherit from Serializable and you're ready to go
  • 🔄 Automatic Type Registration: Classes are automatically registered for deserialization
  • 🛡️ Type Safety: Built-in validation ensures objects can be properly deserialized
  • 🌳 Nested Objects: Automatically handles nested Serializable objects, lists, and dictionaries
  • 🔧 Callable Serialization: Full support for serializing functions, methods, and lambda expressions
  • 🔒 Security: Strict mode prevents deserialization of unknown fields
  • Zero Dependencies: Pure Python with no external dependencies
  • 🎓 Easy to Use: Minimal boilerplate, maximum flexibility

🎯 Perfect For

  • Object Persistence: Save and restore complex object states
  • Configuration Management: Serialize configuration objects to JSON/YAML
  • Data Transfer: Convert objects to dictionaries for API communication
  • State Management: Save application state for recovery
  • Workflow Orchestration: Serialize workflow definitions and states
  • Testing: Create test fixtures from serialized objects

📦 Installation

Quick Install (Recommended)

pip install serilux

That's it! You're ready to go.

Development Setup with uv (Recommended)

This project uses uv for fast dependency management. Install uv first:

curl -LsSf https://astral.sh/uv/install.sh | sh

Then set up the development environment:

Recommended: For active development

# Install package with all development dependencies (recommended)
make dev-install

# Or manually with uv (dev group is installed by default)
uv sync --group docs --all-extras

Alternative: Dependencies only (for CI/CD or code review)

# Create virtual environment and install dependencies only (without installing the package)
# Useful for: CI/CD pipelines, code review, or when you only need development tools
make setup-venv

# Later, if you need to install the package:
make install

Understanding dependency groups vs extras:

  • Dependency groups (dev, docs): Development dependencies that are not published to PyPI. The dev group is installed by default with uv sync.
  • Extras: Currently none, but may be added in the future.

All make commands will automatically use uv if available, otherwise fall back to pip.

Development Install (Legacy - using pip)

For development with all dependencies using pip:

pip install -e ".[dev]"
# Or using Makefile
make dev-install

🚀 Quick Start

Create Your First Serializable Class in 3 Steps

Step 1: Define a Serializable Class

from serilux import Serializable, register_serializable

@register_serializable
class Person(Serializable):
    def __init__(self):
        super().__init__()
        self.name = ""
        self.age = 0
        # Register fields to serialize
        self.add_serializable_fields(["name", "age"])

Step 2: Create and Use Objects

# Create an object
person = Person()
person.name = "Alice"
person.age = 30

# Serialize to dictionary
data = person.serialize()
print(data)
# {'_type': 'Person', 'name': 'Alice', 'age': 30}

Step 3: Deserialize

# Deserialize from dictionary
new_person = Person()
new_person.deserialize(data)
print(new_person.name)  # "Alice"
print(new_person.age)   # 30

🎉 Done! You've created your first serializable class.

💡 Key Features

🔄 Automatic Type Registration

Classes decorated with @register_serializable are automatically registered:

@register_serializable
class MyClass(Serializable):
    def __init__(self):
        super().__init__()
        self.add_serializable_fields(["field1", "field2"])

Class Name Conflict Detection: Serilux automatically detects and prevents class name conflicts. If you try to register a different class with the same name, a ValueError is raised to prevent incorrect deserialization:

@register_serializable
class Processor(Serializable):
    def __init__(self):
        super().__init__()
        self.name = ""
        self.add_serializable_fields(["name"])

# This will raise ValueError: Class name conflict
@register_serializable
class Processor(Serializable):  # Different class, same name
    def __init__(self):
        super().__init__()
        self.value = 0
        self.add_serializable_fields(["value"])

🌳 Nested Objects

Automatically handles nested Serializable objects:

@register_serializable
class Address(Serializable):
    def __init__(self):
        super().__init__()
        self.street = ""
        self.city = ""
        self.add_serializable_fields(["street", "city"])

@register_serializable
class Person(Serializable):
    def __init__(self):
        super().__init__()
        self.name = ""
        self.address = None
        self.add_serializable_fields(["name", "address"])

# Create nested objects
person = Person()
person.name = "Alice"
person.address = Address()
person.address.street = "123 Main St"
person.address.city = "New York"

# Serialize - nested objects are automatically handled
data = person.serialize()

📋 Lists and Dictionaries

Handles lists and dictionaries containing Serializable objects:

@register_serializable
class Team(Serializable):
    def __init__(self):
        super().__init__()
        self.name = ""
        self.members = []  # List of Person objects
        self.add_serializable_fields(["name", "members"])

team = Team()
team.name = "Engineering"
team.members = [person1, person2, person3]

# Serialize - list items are automatically serialized
data = team.serialize()

🔧 Callable Serialization

Serilux supports serializing and deserializing callable objects (functions, methods, lambda expressions):

from serilux import serialize_callable, deserialize_callable, serialize_callable_with_fallback

# Serialize a function
def process_data(data):
    return data.upper()

serialized = serialize_callable(process_data)
restored = deserialize_callable(serialized)
result = restored("hello")  # Returns "HELLO"

# Serialize lambda expression
condition = lambda x: x.get("priority") == "high"
serialized_lambda = serialize_callable_with_fallback(condition)
# Returns: {"_type": "lambda_expression", "expression": "x.get('priority') == 'high'"}

Callable fields in Serializable objects are automatically serialized:

@register_serializable
class Processor(Serializable):
    def __init__(self):
        super().__init__()
        self.handler = None  # Will store a function
        self.add_serializable_fields(["handler"])

processor = Processor()
processor.handler = process_data  # Function is automatically serialized
data = processor.serialize()

🔒 Strict Mode

Enable strict mode to prevent deserialization of unknown fields:

# Strict mode raises error for unknown fields
try:
    person.deserialize(data, strict=True)
except ValueError as e:
    print(f"Error: {e}")

✅ Validation

Validate that objects can be properly deserialized:

from serilux import validate_serializable_tree

# Validate before serialization
validate_serializable_tree(person)

📚 Documentation

📖 Full documentation available at: serilux.readthedocs.io

Documentation Highlights

Build Documentation Locally

pip install -e ".[docs]"
cd docs && make html

🎓 Examples

Check out the examples/ directory for practical examples:

  • basic_usage.py - Your first serializable class
  • advanced_usage.py - Nested objects, lists, and dictionaries
  • callable_serialization.py - Serializing functions, methods, and lambda expressions

Run examples:

python examples/basic_usage.py

🏗️ Project Structure

serilux/
├── serilux/              # Main package
│   ├── __init__.py       # Package initialization
│   └── serializable.py   # Core serialization classes
├── tests/                # Comprehensive test suite
├── examples/             # Usage examples
└── docs/                 # Sphinx documentation

🧪 Testing

Serilux comes with comprehensive tests:

# Run all tests
make test-all

# Run with coverage
make test-cov

# Run specific test suite
pytest tests/

🤝 Contributing

We welcome contributions! Here's how you can help:

  1. Star the project ⭐ - Show your support
  2. Report bugs 🐛 - Help us improve
  3. Suggest features 💡 - Share your ideas
  4. Submit PRs 🔧 - Contribute code

🏢 About Agentsmith

Serilux is part of the Agentsmith open-source ecosystem. Agentsmith is a ToB AI agent and algorithm development platform, currently deployed in multiple highway management companies, securities firms, and regulatory agencies in China. The Agentsmith team is gradually open-sourcing the platform by removing proprietary code and algorithm modules, as well as enterprise-specific customizations, while decoupling the system for modular use by the open-source community.

🌟 Agentsmith Open-Source Projects

  • Varlord ⚙️ - Configuration management library with multi-source support
  • Routilux ⚡ - Event-driven workflow orchestration framework
  • Serilux 📦 - Flexible serialization framework for Python objects
  • Lexilux 🚀 - Unified LLM API client library

These projects are modular components extracted from the Agentsmith platform, designed to be used independently or together to build powerful applications.

📄 License

Serilux is licensed under the Apache License 2.0. See LICENSE for details.

🔗 Links

⭐ Show Your Support

If Serilux helps you build amazing applications, consider giving it a star on GitHub!


Built with ❤️ by the Serilux Team

Making object serialization simple, powerful, and fun.