Callable Serialization Example¶
This example demonstrates serializing and deserializing callable objects (functions, methods, and lambda expressions).
1"""
2Callable serialization example for Serilux.
3
4This example demonstrates:
5- Serializing and deserializing functions
6- Serializing and deserializing methods
7- Serializing lambda expressions
8- Using ObjectRegistry for method deserialization
9"""
10
11from serilux import (
12 ObjectRegistry,
13 Serializable,
14 deserialize_callable,
15 deserialize_lambda_expression,
16 register_serializable,
17 serialize_callable,
18 serialize_callable_with_fallback,
19)
20
21
22# Example 1: Serializing module-level functions
23def process_data(data):
24 """A simple processing function."""
25 return data.upper()
26
27
28def filter_high_priority(item):
29 """Filter function for high priority items."""
30 return item.get("priority") == "high"
31
32
33# Example 2: Serializable class with callable fields
34@register_serializable
35class DataProcessor(Serializable):
36 """A processor with a callable handler."""
37
38 def __init__(self):
39 super().__init__()
40 self.name = ""
41 self.handler = None # Will store a function
42 self.add_serializable_fields(["name", "handler"])
43
44
45@register_serializable
46class ConditionalRouter(Serializable):
47 """A router with a condition function."""
48
49 def __init__(self):
50 super().__init__()
51 self._id = None
52 self.name = ""
53 self.condition = None # Will store a lambda or function
54 self.add_serializable_fields(["name", "condition"])
55
56 def route(self, data):
57 """Route data based on condition."""
58 if self.condition and self.condition(data):
59 return "route_a"
60 return "route_b"
61
62
63def main():
64 """Run the callable serialization example."""
65 print("=== Serilux Callable Serialization Example ===\n")
66
67 # Example 1: Serialize and deserialize a module function
68 print("1. Serializing module-level function...")
69 serialized_func = serialize_callable(process_data)
70 print(f" Serialized: {serialized_func}\n")
71
72 # Deserialize the function
73 deserialized_func = deserialize_callable(serialized_func)
74 print(f" Deserialized function works: {deserialized_func('hello') == 'HELLO'}\n")
75
76 # Example 2: Serialize a function in a Serializable object
77 print("2. Serializing function in Serializable object...")
78 processor = DataProcessor()
79 processor.name = "Uppercase Processor"
80 processor.handler = process_data
81
82 data = processor.serialize()
83 print(f" Processor data: {data}\n")
84
85 # Deserialize
86 new_processor = DataProcessor()
87 new_processor.deserialize(data)
88 print(f" Handler works: {new_processor.handler('test') == 'TEST'}\n")
89
90 # Example 3: Serialize lambda expression
91 print("3. Serializing lambda expression...")
92 condition = lambda x: x.get("priority") == "high"
93 serialized_lambda = serialize_callable_with_fallback(condition)
94 print(f" Serialized lambda: {serialized_lambda}\n")
95
96 # Deserialize lambda
97 deserialized_lambda = deserialize_lambda_expression(serialized_lambda)
98 test_data = {"priority": "high"}
99 print(f" Lambda works: {deserialized_lambda(test_data) is True}\n")
100
101 # Example 4: Serialize lambda expression in Serializable object
102 # Note: To ensure lambda is serialized as lambda_expression (not as function),
103 # we use serialize_callable_with_fallback and store the serialized data directly.
104 # This is useful when you want to preserve the lambda expression for deserialization.
105 print("4. Serializing lambda expression in Serializable object...")
106 router = ConditionalRouter()
107 router._id = "router1"
108 router.name = "Priority Router"
109
110 # Create lambda and serialize it as expression using fallback
111 condition_lambda = lambda x: x.get("priority") == "high"
112 condition_serialized = serialize_callable_with_fallback(condition_lambda)
113 # Store the serialized data directly (this ensures lambda_expression format)
114 router.condition = condition_serialized
115
116 router_data = router.serialize()
117 print(f" Router data: {router_data}\n")
118
119 # Check if condition was serialized as lambda_expression
120 condition_data = router_data.get("condition", {})
121 if condition_data.get("_type") == "lambda_expression":
122 print(" ✓ Condition serialized as lambda_expression\n")
123 else:
124 print(f" Note: Condition serialized as {condition_data.get('_type', 'unknown')}\n")
125
126 # Deserialize with registry
127 new_router = ConditionalRouter()
128 registry = ObjectRegistry()
129 registry.register(new_router, object_id="router1")
130 new_router.deserialize(router_data, registry=registry)
131
132 # The condition should be deserialized as a callable
133 if callable(new_router.condition):
134 test_item = {"priority": "high"}
135 result = new_router.route(test_item)
136 print(f" Router works: {result == 'route_a'}\n")
137 else:
138 print(" ⚠ Condition not deserialized as callable\n")
139
140 # Example 5: Serialize method with ObjectRegistry
141 print("5. Serializing method with ObjectRegistry...")
142
143 @register_serializable
144 class Handler(Serializable):
145 def __init__(self):
146 super().__init__()
147 self._id = "handler1"
148 self.name = ""
149 self.process = self.process_data
150 self.add_serializable_fields(["name", "process"])
151
152 def process_data(self, data):
153 return data.upper()
154
155 handler = Handler()
156 handler.name = "Uppercase Handler"
157 handler_data = handler.serialize()
158 print(f" Handler data: {handler_data}\n")
159
160 # Deserialize with registry
161 new_handler = Handler()
162 registry2 = ObjectRegistry()
163 registry2.register(new_handler, object_id="handler1")
164 new_handler.deserialize(handler_data, registry=registry2)
165
166 print(f" Method works: {new_handler.process('test') == 'TEST'}\n")
167
168 print("✓ All callable serialization examples successful!")
169
170
171if __name__ == "__main__":
172 main()