Skip to main content

Getting Started

Lodum provides a simple, decorator-based API for serializing Python objects to multiple formats. At its core, you use the @lodum decorator to mark classes for serialization.

Defining Data Structures

Use the @lodum decorator on your class with type hints. You can use standard __init__ methods or dataclasses.
from lodum import lodum
from dataclasses import dataclass

@lodum
@dataclass
class User:
    name: str
    age: int
    is_active: bool
Or with a traditional __init__ method:
@lodum
class ServerConfig:
    def __init__(self, host: str, port: int, services: list[str]):
        self.host = host
        self.port = port
        self.services = services
Type hints are required - Lodum uses them to understand your data structure and generate optimized serialization code.

Serializing to JSON

Use json.dumps() to convert an instance to a JSON string:
from lodum import json

user = User(name="Alex", age=30, is_active=True)
json_string = json.dumps(user)
print(json_string)
# Output: {"name": "Alex", "age": 30, "is_active": true}

Deserializing from JSON

Use json.loads() to parse JSON back into Python objects:
json_data = '{"name": "Barbara", "age": 25, "is_active": false}'
barb = json.loads(User, json_data)

print(f"Name: {barb.name}, Age: {barb.age}, Active: {barb.is_active}")
# Output: Name: Barbara, Age: 25, Active: False
Notice that loads() requires the target class as the first argument. This enables Lodum to perform type validation and instantiate the correct class.

Working with Primitives

Lodum handles primitive types directly without requiring a class definition:
# Serialize primitives
assert json.dumps(123) == "123"
assert json.dumps("hello") == '"hello"'
assert json.dumps(3.14) == "3.14"
assert json.dumps(True) == "true"
assert json.dumps(None) == "null"

# Deserialize primitives
assert json.loads(int, "123") == 123
assert json.loads(str, '"hello"') == "hello"
assert json.loads(float, "3.14") == 3.14
assert json.loads(bool, "true") is True
assert json.loads(type(None), "null") is None

Nested Objects

Lodum automatically handles nested @lodum-decorated classes:
@lodum
class Simple:
    def __init__(self, a: int, b: str):
        self.a = a
        self.b = b

@lodum
class Nested:
    def __init__(self, simple: Simple, c: bool):
        self.simple = simple
        self.c = c

nested = Nested(simple=Simple(a=42, b="hello"), c=True)
json_str = json.dumps(nested)
# {"simple": {"a": 42, "b": "hello"}, "c": true}

# Deserialize
restored = json.loads(Nested, json_str)
assert restored.simple.a == 42

Multiple Format Support

Define your data structure once and serialize to any supported format:
from lodum import json, yaml, toml, msgpack

user = User(name="Alex", age=30, is_active=True)

# Encode to different formats
json_output = json.dumps(user)
yaml_output = yaml.dumps(user)
toml_output = toml.dumps(user)
msgpack_output = msgpack.dumps(user)

Round-Trip Conversions

Lodum ensures reliable round-trip conversions between formats:
import json as std_json
from lodum import lodum, json, yaml

@lodum
class ServerConfig:
    def __init__(self, host: str, port: int, services: list[str]):
        self.host = host
        self.port = port
        self.services = services

# Start with JSON
original_json = '{"host": "127.0.0.1", "port": 8080, "services": ["users", "products"]}'

# Decode JSON to Python object
config_from_json = json.loads(ServerConfig, original_json)

# Encode to YAML
yaml_output = yaml.dumps(config_from_json)

# Decode YAML back to Python object
config_from_yaml = yaml.loads(ServerConfig, yaml_output)

# Encode back to JSON
final_json = json.dumps(config_from_yaml)

# Verify consistency
assert std_json.loads(original_json) == std_json.loads(final_json)

Working with Dictionaries

Convert objects to and from plain Python dictionaries:
import lodum

@lodum
class User:
    def __init__(self, user_id: int, name: str):
        self.user_id = user_id
        self.name = name

user = User(user_id=1, name="Alex")

# Convert to dictionary
data = lodum.asdict(user)
print(data)  # {"user_id": 1, "name": "Alex"}

# Convert from dictionary
new_user = lodum.fromdict(User, {"user_id": 2, "name": "Sam"})
assert new_user.user_id == 2
Use asdict() and fromdict() when you need to work with plain Python data structures without string encoding.

Error Handling

Lodum provides detailed error messages with path information:
from lodum import lodum, json
from lodum.exception import DeserializationError

@lodum
class User:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age

json_data = '{"name": "Alex", "age": "not_an_int"}'

try:
    json.loads(User, json_data)
except DeserializationError as e:
    print(e)
    # Output: Error at age: Expected int, got str
The path tracking works through nested objects, lists, and dictionaries (e.g., root.users[2].id).

Next Steps

Advanced Features

Learn about field customization, validation, and type handling

Streaming

Handle large datasets with streaming serialization

Build docs developers (and LLMs) love